diff --git a/reactos/drivers/filesystems/ext2/ext2fs.rc b/reactos/drivers/filesystems/ext2/ext2fs.rc new file mode 100644 index 00000000000..0cbc172a885 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/ext2fs.rc @@ -0,0 +1,7 @@ +/* $Id: ext2fs.rc 12852 2005-01-06 13:58:04Z mf $ */ + +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "Linux ext2 IFS Driver\0" +#define REACTOS_STR_INTERNAL_NAME "ext2fs\0" +#define REACTOS_STR_ORIGINAL_FILENAME "ext2fs.sys\0" +#include diff --git a/reactos/drivers/filesystems/ext2/inc/errmsg.h b/reactos/drivers/filesystems/ext2/inc/errmsg.h new file mode 100644 index 00000000000..8f8ac96eeb2 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/errmsg.h @@ -0,0 +1,68 @@ +/************************************************************************* +* +* File: errmsg.msg +* +* Product: Ext2 FSD +* +* Module: Ext2 FSD Event Log Messages +* +* Description: +* Contains error strings in a format understandable to the message compiler. +* Please compile (using mc) with the -c option which will set the +* "Customer" bit in all errors. +* Use values beginning at 0xA000 (e.g. 0xA001) for the Ext2 FSD +* errors. +* Do NOT use %1 for insertion strings. The I/O manager assumes that +* the first insertion string is the name of the driver/device. +* +* +*************************************************************************/ +// +// Values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// + + +// +// Define the severity codes +// +#define STATUS_SEVERITY_WARNING 0x2 +#define STATUS_SEVERITY_SUCCESS 0x0 +#define STATUS_SEVERITY_INFORMATIONAL 0x1 +#define STATUS_SEVERITY_ERROR 0x3 + + +// +// MessageId: EXT2_ERROR_INTERNAL_ERROR +// +// MessageText: +// +// The Ext2 FSD encountered an internal error. Please check log data information. +// +#define EXT2_ERROR_INTERNAL_ERROR ((ULONG)0xE004A001L) + diff --git a/reactos/drivers/filesystems/ext2/inc/ext2_fs.h b/reactos/drivers/filesystems/ext2/inc/ext2_fs.h new file mode 100644 index 00000000000..4a545d4d307 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/ext2_fs.h @@ -0,0 +1,615 @@ +/* + * linux/include/linux/ext2_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT2_FS_H +#define _LINUX_EXT2_FS_H + +// #include + +/* + * 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 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 */ diff --git a/reactos/drivers/filesystems/ext2/inc/ext2fsd.h b/reactos/drivers/filesystems/ext2/inc/ext2fsd.h new file mode 100644 index 00000000000..81c246d43d5 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/ext2fsd.h @@ -0,0 +1,250 @@ +/************************************************************************* +* +* File: ext2fsd.h +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* The main include file for the Ext2 file system driver. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + + +#ifndef _EXT2_FSD_H_ +#define _EXT2_FSD_H_ + +#define EXT2_POOL_WITH_TAG + + +// some constant definitions +#define EXT2_PANIC_IDENTIFIER (0x86427531) + +// any directory information EXT2 obtains from the local file system +// will use a buffer of the following size ... (in KB) +#define EXT2_READ_DIR_BUFFER_LENGTH (512) +#define EXT2_MAXCLOSABLE_FCBS_UL 20 +#define EXT2_MAXCLOSABLE_FCBS_LL 10 + +// Some type definitions... +// These are used later... + +typedef unsigned char UCHAR; +typedef unsigned int UINT; +typedef UCHAR BYTE; +typedef UCHAR BOOLEAN; // winnt +typedef BOOLEAN * PBOOLEAN; // winnt +typedef void * PVOID64; // winnt +typedef long LONG; +typedef LONG HRESULT; + + +#if defined(_M_IX86) +#define FASTCALL _fastcall +#else +#define FASTCALL +#endif + + + +// Common include files - should be in the include dir of the MS supplied IFS Kit +#include +#include + + +/* 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_ diff --git a/reactos/drivers/filesystems/ext2/inc/ext2metadata.h b/reactos/drivers/filesystems/ext2/inc/ext2metadata.h new file mode 100644 index 00000000000..bbe240e9143 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/ext2metadata.h @@ -0,0 +1,115 @@ +/************************************************************************* +* +* File: ext2metadata.h +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains the definitions for the Ext2 Metadata structures. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#ifndef EXT2_METADATA_STRUCTURES +#define EXT2_METADATA_STRUCTURES + +// +// Some type definitions... +// These are used in the ext2_fs.h header file +// +typedef unsigned int __u32 ; +typedef signed int __s32 ; +typedef unsigned short int __u16 ; +typedef signed short int __s16 ; +typedef unsigned char __u8 ; + +// +//****************************************************** +// +// Using Remy Card's (slightly modified) Ext2 header... +// +#include "ext2_fs.h" +// +//****************************************************** +// + +typedef struct ext2_super_block EXT2_SUPER_BLOCK; +typedef EXT2_SUPER_BLOCK * PEXT2_SUPER_BLOCK; + +typedef struct ext2_inode EXT2_INODE; +typedef EXT2_INODE * PEXT2_INODE; + +typedef struct ext2_group_desc EXT2_GROUP_DESCRIPTOR; +typedef EXT2_GROUP_DESCRIPTOR * PEXT2_GROUP_DESCRIPTOR; + +typedef struct ext2_dir_entry_2 EXT2_DIR_ENTRY; +typedef EXT2_DIR_ENTRY * PEXT2_DIR_ENTRY; + +// +// Ext2 Supported File Types... +// +#define IMODE_FIFO 0x01 +#define IMODE_CHARDEV 0x02 +#define IMODE_DIR 0x04 +#define IMODE_BLOCKDEV 0x06 +#define IMODE_FILE 0x08 +#define IMODE_SLINK 0x0A +#define IMODE_SOCKET 0x0C + +#define _MKMODE(m) ( ( (m) >> 12 ) & 0x000F) +#define Ext2IsModeRegularFile(m) ( _MKMODE(m) == IMODE_FILE ) +#define Ext2IsModeDirectory(m) ( _MKMODE(m) == IMODE_DIR ) +#define Ext2IsModeSymbolicLink(m) ( _MKMODE(m) == IMODE_SLINK ) +#define Ext2IsModePipe(m) ( _MKMODE(m) == IMODE_FIFO ) +#define Ext2IsModeCharacterDevice(m) ( _MKMODE(m) == IMODE_CHARDEV ) +#define Ext2IsModeBlockDevice(m) ( _MKMODE(m) == IMODE_BLOCKDEV ) +#define Ext2IsModeSocket(m) ( _MKMODE(m) == IMODE_SOCKET ) + +#define Ext2IsModeHidden(m) ( (m & 0x124) == 0) // No Read Permission +#define Ext2IsModeReadOnly(m) ( (m & 0x92) == 0) // No write Permission + +#define Ext2SetModeHidden(m) m = (m & (~0x124)); // Turn off Read Permission +#define Ext2SetModeReadOnly(m) m = (m & (~0x92)); // Turn off write Permission +#define Ext2SetModeReadWrite(m) m = (m & 0x1ff); // Set read/write Permission + + +// +// Define the Packed and Unpacked BIOS Parameter Block +// +typedef struct _PACKED_BIOS_PARAMETER_BLOCK { + UCHAR BytesPerSector[2]; // offset = 0x000 0 + UCHAR SectorsPerCluster[1]; // offset = 0x002 2 + UCHAR ReservedSectors[2]; // offset = 0x003 3 + UCHAR Fats[1]; // offset = 0x005 5 + UCHAR RootEntries[2]; // offset = 0x006 6 + UCHAR Sectors[2]; // offset = 0x008 8 + UCHAR Media[1]; // offset = 0x00A 10 + UCHAR SectorsPerFat[2]; // offset = 0x00B 11 + UCHAR SectorsPerTrack[2]; // offset = 0x00D 13 + UCHAR Heads[2]; // offset = 0x00F 15 + UCHAR HiddenSectors[4]; // offset = 0x011 17 + UCHAR LargeSectors[4]; // offset = 0x015 21 +} PACKED_BIOS_PARAMETER_BLOCK; // sizeof = 0x019 25 +typedef PACKED_BIOS_PARAMETER_BLOCK *PPACKED_BIOS_PARAMETER_BLOCK; + +// +// Define the boot sector +// +typedef struct _PACKED_BOOT_SECTOR { + UCHAR Jump[3]; // offset = 0x000 0 + UCHAR Oem[8]; // offset = 0x003 3 + PACKED_BIOS_PARAMETER_BLOCK PackedBpb; // offset = 0x00B 11 + UCHAR PhysicalDriveNumber; // offset = 0x024 36 + UCHAR CurrentHead; // offset = 0x025 37 + UCHAR Signature; // offset = 0x026 38 + UCHAR Id[4]; // offset = 0x027 39 + UCHAR VolumeLabel[11]; // offset = 0x02B 43 + UCHAR SystemId[8]; // offset = 0x036 54 +} PACKED_BOOT_SECTOR; // sizeof = 0x03E 62 + +typedef PACKED_BOOT_SECTOR *PPACKED_BOOT_SECTOR; + + +#endif diff --git a/reactos/drivers/filesystems/ext2/inc/protos.h b/reactos/drivers/filesystems/ext2/inc/protos.h new file mode 100644 index 00000000000..1cb7c134d62 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/protos.h @@ -0,0 +1,782 @@ +/************************************************************************* +* +* File: protos.h +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains the prototypes for functions in this sample FSD. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#ifndef _EXT2_PROTOS_H_ +#define _EXT2_PROTOS_H_ + +#ifdef __REACTOS__ +typedef PIO_STACK_LOCATION PEXTENDED_IO_STACK_LOCATION; +#endif + +/************************************************************************* +* Prototypes for the file sfsdinit.c +*************************************************************************/ +extern NTSTATUS STDCALL DriverEntry( + PDRIVER_OBJECT DriverObject, // created by the I/O sub-system + PUNICODE_STRING RegistryPath); // path to the registry key + +extern void STDCALL Ext2FsdInitializeFunctionPointers( + PDRIVER_OBJECT DriverObject); // created by the I/O sub-system + + +extern VOID STDCALL Ext2QueueHandlerThread( + IN PVOID StartContext); + +/************************************************************************* +* Prototypes for the file fsctrl.c +*************************************************************************/ + +extern NTSTATUS STDCALL Ext2FileSystemControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +extern NTSTATUS STDCALL Ext2VerifyVolume ( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ); + + +/************************************************************************* +* Prototypes for the file create.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Create( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonCreate( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ); + +extern NTSTATUS STDCALL Ext2OpenVolume( + PtrExt2VCB PtrVCB, // volume to be opened + PtrExt2IrpContext PtrIrpContext, // IRP context + PIRP PtrIrp, // original/user IRP + unsigned short ShareAccess, // share access + PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) + PFILE_OBJECT PtrNewFileObject); // I/O Mgr. created file object + +extern NTSTATUS STDCALL Ext2OpenRootDirectory( + PtrExt2VCB PtrVCB, // volume to be opened + PtrExt2IrpContext PtrIrpContext, // IRP context + PIRP PtrIrp, // original/user IRP + unsigned short ShareAccess, // share access + PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) + PFILE_OBJECT PtrNewFileObject); // I/O Mgr. created file object + +extern void STDCALL Ext2InitializeFCB( + PtrExt2FCB PtrNewFCB, // FCB structure to be initialized + PtrExt2VCB PtrVCB, // logical volume (VCB) pointer + PtrExt2ObjectName PtrObjectName, // name of the object + uint32 Flags, // is this a file/directory, etc. + PFILE_OBJECT PtrFileObject);// optional file object to be initialized + +extern PtrExt2FCB STDCALL Ext2LocateChildFCBInCore( + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrName, + ULONG ParentInodeNo ); + +extern PtrExt2FCB STDCALL Ext2LocateFCBInCore( + PtrExt2VCB PtrVCB, + ULONG InodeNo ); + + +extern ULONG STDCALL Ext2LocateFileInDisk( + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrCurrentName, + PtrExt2FCB PtrParentFCB, + ULONG *Type ); + +extern ULONG STDCALL Ext2CreateFile( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrName, + PtrExt2FCB PtrParentFCB, + ULONG Type); + +extern BOOLEAN STDCALL Ext2OverwriteFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext); + +extern BOOLEAN STDCALL Ext2SupersedeFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext); + +/************************************************************************* +* Prototypes for the file misc.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2InitializeZones( +void); + +extern void STDCALL Ext2DestroyZones( +void); + +extern BOOLEAN STDCALL Ext2IsIrpTopLevel( +PIRP Irp); // the IRP sent to our dispatch routine + +extern long STDCALL Ext2ExceptionFilter( +PtrExt2IrpContext PtrIrpContext, +PEXCEPTION_POINTERS PtrExceptionPointers); + +extern NTSTATUS STDCALL Ext2ExceptionHandler( +PtrExt2IrpContext PtrIrpContext, +PIRP Irp); + +extern void STDCALL Ext2LogEvent( +NTSTATUS Ext2EventLogId, // the Ext2 private message id +NTSTATUS RC); // any NT error code we wish to log ... + +extern PtrExt2ObjectName STDCALL Ext2AllocateObjectName( +void); + +extern void STDCALL Ext2ReleaseObjectName( +PtrExt2ObjectName PtrObjectName); + +extern PtrExt2CCB STDCALL Ext2AllocateCCB( +void ); + +extern PtrExt2FCB STDCALL Ext2GetUsedFCB( +PtrExt2VCB PtrVCB ); + +extern BOOLEAN STDCALL Ext2CloseClosableFCB( +PtrExt2FCB PtrFCB ); + +extern void STDCALL Ext2ReleaseCCB( +PtrExt2CCB PtrCCB); + +extern PtrExt2FCB STDCALL Ext2AllocateFCB( +void); + +extern NTSTATUS STDCALL Ext2CreateNewFCB( +PtrExt2FCB *ReturnedFCB, +LARGE_INTEGER AllocationSize, +LARGE_INTEGER EndOfFile, +PFILE_OBJECT PtrFileObject, +PtrExt2VCB PtrVCB, +PtrExt2ObjectName PtrObjectName); + +extern NTSTATUS STDCALL Ext2CreateNewCCB( +PtrExt2CCB *ReturnedCCB, +PtrExt2FCB PtrFCB, +PFILE_OBJECT PtrFileObject); + +extern void STDCALL Ext2ReleaseFCB( +PtrExt2FCB PtrFCB); + +extern PtrExt2FileLockInfo STDCALL Ext2AllocateByteLocks( +void); + +extern void STDCALL Ext2ReleaseByteLocks( +PtrExt2FileLockInfo PtrByteLocks); + +extern PtrExt2IrpContext STDCALL Ext2AllocateIrpContext( +PIRP Irp, +PDEVICE_OBJECT PtrTargetDeviceObject); + +extern void STDCALL Ext2ReleaseIrpContext( +PtrExt2IrpContext PtrIrpContext); + +extern NTSTATUS STDCALL Ext2PostRequest( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern void STDCALL Ext2CommonDispatch( +void *Context); // actually an IRPContext structure + +extern void STDCALL Ext2InitializeVCB( +PDEVICE_OBJECT PtrVolumeDeviceObject, +PDEVICE_OBJECT PtrTargetDeviceObject, +PVPB PtrVPB, +PLARGE_INTEGER AllocationSize); + +extern void STDCALL Ext2CompleteRequest( + IN PIRP Irp OPTIONAL, + IN NTSTATUS Status + ); + +extern NTSTATUS STDCALL Ext2DenyAccess( + IN PIRP Irp + ); +extern NTSTATUS STDCALL Ext2GetFCB_CCB_VCB_FromFileObject( + IN PFILE_OBJECT PtrFileObject, + OUT PtrExt2FCB *PPtrFCB, + OUT PtrExt2CCB *PPtrCCB, + OUT PtrExt2VCB *PPtrVCB ); + +extern void STDCALL Ext2CopyUnicodeString( + IN OUT PUNICODE_STRING PtrDestinationString, + IN PUNICODE_STRING PtrSourceString ); + +extern void STDCALL Ext2CopyWideCharToUnicodeString( + IN OUT PUNICODE_STRING PtrDestinationString, + IN PCWSTR PtrSourceString ); + +extern void STDCALL Ext2CopyCharToUnicodeString( + IN OUT PUNICODE_STRING PtrDestinationString, + IN PCSTR PtrSourceString, + IN USHORT SourceStringLength ); + +extern void STDCALL Ext2CopyZCharToUnicodeString( + IN OUT PUNICODE_STRING PtrDestinationString, + IN PCSTR PtrSourceString ); + +extern void STDCALL Ext2DeallocateUnicodeString( + PUNICODE_STRING PtrUnicodeString ); + +extern void STDCALL Ext2ZerooutUnicodeString( + PUNICODE_STRING PtrUnicodeString ); + +extern BOOLEAN STDCALL Ext2SaveBCB( + PtrExt2IrpContext PtrIrpContext, + PBCB PtrBCB, + PFILE_OBJECT PtrFileObject); + +extern BOOLEAN STDCALL Ext2FlushSavedBCBs( + PtrExt2IrpContext PtrIrpContext); + +extern BOOLEAN STDCALL AssertBCB( + PBCB PtrBCB); + +extern ULONG STDCALL Ext2Align( + ULONG NumberToBeAligned, + ULONG Alignment); + +extern LONGLONG STDCALL Ext2Align64( + LONGLONG NumberToBeAligned, + LONGLONG Alignment); + +extern ULONG STDCALL Ext2GetCurrentTime(); + +/************************************************************************* +* Prototypes for the file cleanup.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Cleanup( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonCleanup( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ); + +/************************************************************************* +* Prototypes for the file close.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Close( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonClose( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ); + +/************************************************************************* +* Prototypes for the file read.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Read( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonRead( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ); + +extern void * STDCALL Ext2GetCallersBuffer( +PIRP PtrIrp); + +extern NTSTATUS STDCALL Ext2LockCallersBuffer( +PIRP PtrIrp, +BOOLEAN IsReadOperation, +uint32 Length); + +extern void STDCALL Ext2MdlComplete( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PIO_STACK_LOCATION PtrIoStackLocation, +BOOLEAN ReadCompletion); + +/************************************************************************* +* Prototypes for the file write.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Write( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonWrite( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern void STDCALL Ext2DeferredWriteCallBack ( +void *Context1, // Should be PtrIrpContext +void *Context2); // Should be PtrIrp + +/************************************************************************* +* Prototypes for the file fileinfo.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2FileInfo( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonFileInfo( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern NTSTATUS STDCALL Ext2GetBasicInformation( + PtrExt2FCB PtrFCB, + PFILE_BASIC_INFORMATION PtrBuffer, + long *PtrReturnedLength); + +extern NTSTATUS STDCALL Ext2GetStandardInformation( + PtrExt2FCB PtrFCB, + PFILE_STANDARD_INFORMATION PtrStdInformation, + long *PtrReturnedLength); + +extern NTSTATUS STDCALL Ext2GetNetworkOpenInformation( + PtrExt2FCB PtrFCB, + PFILE_NETWORK_OPEN_INFORMATION PtrNetworkOpenInformation, + long *PtrReturnedLength ); + +extern NTSTATUS STDCALL Ext2GetFullNameInformation( + PtrExt2FCB PtrFCB, + PtrExt2CCB PtrCCB, + PFILE_NAME_INFORMATION PtrNameInformation, + long *PtrReturnedLength); + +extern NTSTATUS STDCALL Ext2SetBasicInformation( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + PFILE_BASIC_INFORMATION PtrFileInformation ); + +extern NTSTATUS STDCALL Ext2SetDispositionInformation( +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB, +PtrExt2VCB PtrVCB, +PFILE_OBJECT PtrFileObject, +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PFILE_DISPOSITION_INFORMATION PtrBuffer); + +extern NTSTATUS STDCALL Ext2SetAllocationInformation( +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB, +PtrExt2VCB PtrVCB, +PFILE_OBJECT PtrFileObject, +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PFILE_ALLOCATION_INFORMATION PtrBuffer); + +/************************************************************************* +* Prototypes for the file flush.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Flush( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonFlush( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern void STDCALL Ext2FlushAFile( +PtrExt2NTRequiredFCB PtrReqdFCB, +PIO_STATUS_BLOCK PtrIoStatus); + +extern void STDCALL Ext2FlushLogicalVolume( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PtrExt2VCB PtrVCB); + +extern NTSTATUS STDCALL Ext2FlushCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP PtrIrp, +PVOID Context); + +/************************************************************************* +* Prototypes for the file dircntrl.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2DirControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonDirControl( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern NTSTATUS STDCALL Ext2QueryDirectory( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, +PFILE_OBJECT PtrFileObject, +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB); + +extern NTSTATUS STDCALL Ext2NotifyChangeDirectory( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, +PFILE_OBJECT PtrFileObject, +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB); + +/************************************************************************* +* Prototypes for the file devcntrl.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2DeviceControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonDeviceControl( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +extern NTSTATUS STDCALL Ext2DevIoctlCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP PtrIrp, +void *Context); + +extern NTSTATUS STDCALL Ext2HandleQueryPath( +void *BufferPointer); + +/************************************************************************* +* Prototypes for the file shutdown.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2Shutdown( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +extern NTSTATUS STDCALL Ext2CommonShutdown( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp); + +/************************************************************************* +* Prototypes for the file volinfo.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2QueryVolInfo( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp); // I/O Request Packet + +NTSTATUS STDCALL Ext2SetVolInfo( + IN PDEVICE_OBJECT DeviceObject, // the logical volume device object + IN PIRP Irp); // I/O Request Packet + + +/************************************************************************* +* Prototypes for the file fastio.c +*************************************************************************/ +extern BOOLEAN STDCALL Ext2FastIoCheckIfPossible( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +IN BOOLEAN CheckForReadOperation, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +OUT PVOID Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +OUT PVOID Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoQueryBasicInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_BASIC_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoQueryStdInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_STANDARD_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoLock( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN PLARGE_INTEGER Length, +PEPROCESS ProcessId, +ULONG Key, +BOOLEAN FailImmediately, +BOOLEAN ExclusiveLock, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoUnlockSingle( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN PLARGE_INTEGER Length, +PEPROCESS ProcessId, +ULONG Key, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoUnlockAll( +IN PFILE_OBJECT FileObject, +PEPROCESS ProcessId, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoUnlockAllByKey( +IN PFILE_OBJECT FileObject, +PEPROCESS ProcessId, +ULONG Key, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern void STDCALL Ext2FastIoAcqCreateSec( +IN PFILE_OBJECT FileObject); + +extern void STDCALL Ext2FastIoRelCreateSec( +IN PFILE_OBJECT FileObject); + +extern BOOLEAN STDCALL Ext2AcqLazyWrite( +IN PVOID Context, +IN BOOLEAN Wait); + +extern void STDCALL Ext2RelLazyWrite( +IN PVOID Context); + +extern BOOLEAN STDCALL Ext2AcqReadAhead( +IN PVOID Context, +IN BOOLEAN Wait); + +extern void STDCALL Ext2RelReadAhead( +IN PVOID Context); + +// the remaining are only valid under NT Version 4.0 and later +#if(_WIN32_WINNT >= 0x0400) + +extern BOOLEAN STDCALL Ext2FastIoQueryNetInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoMdlRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL *MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoMdlReadComplete( +IN PFILE_OBJECT FileObject, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoPrepareMdlWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL *MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject); + +extern BOOLEAN STDCALL Ext2FastIoMdlWriteComplete( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS STDCALL Ext2FastIoAcqModWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER EndingOffset, +OUT PERESOURCE *ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS STDCALL Ext2FastIoRelModWrite( +IN PFILE_OBJECT FileObject, +IN PERESOURCE ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS STDCALL Ext2FastIoAcqCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject); + +extern NTSTATUS STDCALL Ext2FastIoRelCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject); + +#endif // (_WIN32_WINNT >= 0x0400) + +/************************************************************************* +* Prototypes for the file DiskIO.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2ReadLogicalBlocks( +PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object +VOID *Buffer, // The Buffer that takes the data read in +LARGE_INTEGER StartLogicalBlock, // The logical block from which reading is to start +unsigned int NoOfLogicalBlocks); // The no. of logical blocks to be read + +extern NTSTATUS STDCALL Ext2ReadPhysicalBlocks( + PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object + VOID *Buffer, // The Buffer that takes the data read in + LARGE_INTEGER StartBlock, // The Physical block from which reading is to start + unsigned int NoOfBlocks); // The no. of Physical blocks to be read + +/************************************************************************* +* Prototypes for the file metadata.c +*************************************************************************/ + +extern void STDCALL Ext2InitializeFCBInodeInfo ( + PtrExt2FCB PtrFCB ); + +extern NTSTATUS STDCALL Ext2ReadInode( + PtrExt2VCB PtrVcb, // the Volume Control Block + uint32 InodeNo, // The Inode no + PEXT2_INODE PtrInode ); // The Inode Buffer + +extern NTSTATUS STDCALL Ext2WriteInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVcb, // the Volume Control Block + uint32 InodeNo, // The Inode no + PEXT2_INODE PtrInode // The Inode Buffer + ); + +extern ULONG STDCALL Ext2AllocInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG ParentINodeNo ); + +extern BOOLEAN STDCALL Ext2DeallocInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG INodeNo ); + +extern BOOLEAN STDCALL Ext2MakeNewDirectoryEntry( + PtrExt2IrpContext PtrIrpContext, // The Irp context + PtrExt2FCB PtrParentFCB, // Parent Folder FCB + PFILE_OBJECT PtrFileObject, // Parent Folder Object + PUNICODE_STRING PtrName, // New entry's name + ULONG Type, // The type of the new entry + ULONG NewInodeNo); // The inode no of the new entry... + +extern BOOLEAN STDCALL Ext2FreeDirectoryEntry( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrParentFCB, + PUNICODE_STRING PtrName); + +extern BOOLEAN STDCALL Ext2AddBlockToFile( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + BOOLEAN UpdateFileSize); + +extern BOOLEAN STDCALL Ext2ReleaseDataBlocks( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext); + +extern BOOLEAN STDCALL Ext2TruncateFileAllocationSize( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + PLARGE_INTEGER PtrAllocationSize ); + +extern ULONG STDCALL Ext2AllocBlock( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG Count); + +extern BOOLEAN STDCALL Ext2DeallocBlock( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG BlockNo); + +extern BOOLEAN STDCALL Ext2UpdateFileSize( + PtrExt2IrpContext PtrIrpContext, + PFILE_OBJECT PtrFileObject, + PtrExt2FCB PtrFCB); + + +extern BOOLEAN STDCALL Ext2DeleteFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext); + +extern BOOLEAN STDCALL Ext2IsDirectoryEmpty( + PtrExt2FCB PtrFCB, + PtrExt2CCB PtrCCB, + PtrExt2IrpContext PtrIrpContext); + +extern NTSTATUS STDCALL Ext2RenameOrLinkFile( + PtrExt2FCB PtrSourceFCB, + PFILE_OBJECT PtrSourceFileObject, + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PFILE_RENAME_INFORMATION PtrRenameInfo); +/************************************************************************* +* Prototypes for the file io.c +*************************************************************************/ +extern NTSTATUS STDCALL Ext2PassDownSingleReadWriteIRP( + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PtrExt2VCB PtrVCB, + LARGE_INTEGER ByteOffset, + uint32 ReadWriteLength, + BOOLEAN SynchronousIo); + +extern NTSTATUS STDCALL Ext2PassDownMultiReadWriteIRP( + PEXT2_IO_RUN PtrIoRuns, + UINT Count, + ULONG TotalReadWriteLength, + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + BOOLEAN SynchronousIo); + +extern NTSTATUS STDCALL Ext2SingleSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ); + +extern NTSTATUS STDCALL Ext2SingleAsyncCompletionRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ); + +extern NTSTATUS STDCALL Ext2MultiSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt); + +extern NTSTATUS STDCALL Ext2MultiAsyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt); + +#endif // _EXT2_PROTOS_H_ diff --git a/reactos/drivers/filesystems/ext2/inc/resource.h b/reactos/drivers/filesystems/ext2/inc/resource.h new file mode 100644 index 00000000000..9c490bf5b6c --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by D:\Work\VC\Drivers\ext2FSD\src\ext2.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/reactos/drivers/filesystems/ext2/inc/struct.h b/reactos/drivers/filesystems/ext2/inc/struct.h new file mode 100644 index 00000000000..1b4e83d6516 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/struct.h @@ -0,0 +1,674 @@ +/************************************************************************* +* +* File: struct.h +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* This file contains structure definitions for the sample file system +* driver. Note that all structures are prefixed with the letters +* "Ext2". The structures are all aligned using normal alignment +* used by the compiler (typically quad-word aligned). +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#ifndef _EXT2_STRUCTURES_H_ +#define _EXT2_STRUCTURES_H_ + +/************************************************************************** + some useful definitions +**************************************************************************/ +#ifdef _CPU_X86_ +typedef char int8; +typedef short int16; +typedef int int32; + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; + +typedef PVOID PBCB; + +// we will use the LARGE_INTEGER structure as defined by NT + +#else // Please define appropriate types here + +!!!! You must define your types here for compilation to proceed !!!! + +#endif // if _CPU_X86_ + +/************************************************************************** + some empty typedefs defined here so we can reference them easily +**************************************************************************/ +struct _Ext2Identifier; +struct _Ext2ObjectName; +struct _Ext2ContextControlBlock; +struct _Ext2NTRequiredFCB; +struct _Ext2DiskDependentFCB; +struct _Ext2FileControlBlock; +struct _Ext2FileByteLocks; +struct _Ext2VolumeControlBlock; +struct _Ext2IrpContext; +struct _Ext2Data; + +/************************************************************************** + each structure has a unique "node type" or signature associated with it +**************************************************************************/ +#define EXT2_NODE_TYPE_OBJECT_NAME (0xfdecba01) +#define EXT2_NODE_TYPE_CCB (0xfdecba02) +#define EXT2_NODE_TYPE_FCB (0xfdecba03) +#define EXT2_NODE_TYPE_LOCKS (0xfdecba04) +#define EXT2_NODE_TYPE_VCB (0xfdecba05) +#define EXT2_NODE_TYPE_IRP_CONTEXT (0xfdecba06) +#define EXT2_NODE_TYPE_GLOBAL_DATA (0xfdecba07) +#define EXT2_NODE_TYPE_IO_CONTEXT (0xfdecba08) +#define EXT2_NODE_TYPE_SAVED_BCB (0xfdecba09) +#define EXT2_NODE_TYPE_FREED (0x10101010) +#define EXT2_NODE_TYPE_INVALID (0x10101010) + +/************************************************************************** + every structure has a node type, and a node size associated with it. + The node type serves as a signature field. The size is used for + consistency checking ... +**************************************************************************/ +typedef struct _Ext2Identifier { + uint32 NodeType; // a 32 bit identifier for the structure + uint32 NodeSize; // computed as sizeof(structure) +} Ext2Identifier, *PtrExt2Identifier; + +/************************************************************************** + Structures for byte-range lock support. +**************************************************************************/ +typedef struct Ext2FileLockAnchor { + LIST_ENTRY GrantedFileLockList; + LIST_ENTRY PendingFileLockList; +} Ext2FileLockAnchor, *PtrExt2FileLockAnchor; + +typedef struct Ext2FileLockInfo { + Ext2Identifier NodeIdentifier; + uint32 FileLockFlags; + PVOID OwningProcess; + LARGE_INTEGER StartingOffset; + LARGE_INTEGER Length; + LARGE_INTEGER EndingOffset; + ULONG Key; + BOOLEAN ExclusiveLock; + PIRP PendingIRP; + LIST_ENTRY NextFileLockEntry; +} Ext2FileLockInfo, *PtrExt2FileLockInfo; + +#define EXT2_BYTE_LOCK_NOT_FROM_ZONE (0x80000000) +#define EXT2_BYTE_LOCK_IS_PENDING (0x00000001) + +/************************************************************************** + Every open on-disk object must have a name associated with it + This name has two components: + (a) the path-name (prefix) that leads to this on-disk object + (b) the name of the object itself + Note that with multiply linked objects, a single object might be + associated with more than one name structure. + This sample FSD does not correctly support multiply linked objects. + + This structure must be quad-word aligned because it is zone allocated. +**************************************************************************/ +typedef struct _Ext2ObjectName { + Ext2Identifier NodeIdentifier; + uint32 ObjectNameFlags; + // an absolute pathname of the object is stored below + UNICODE_STRING ObjectName; +} Ext2ObjectName, *PtrExt2ObjectName; + +#define EXT2_OB_NAME_NOT_FROM_ZONE (0x80000000) + +/************************************************************************** + Each file open instance is represented by a context control block. + For each successful create/open request; a file object and a CCB will + be created. + For open operations performed internally by the FSD, there may not + exist file objects; but a CCB will definitely be created. + + This structure must be quad-word aligned because it is zone allocated. +**************************************************************************/ +typedef struct _Ext2ContextControlBlock { + Ext2Identifier NodeIdentifier; + // ptr to the associated FCB + struct _Ext2FileControlBlock *PtrFCB; + // all CCB structures for a FCB are linked together + LIST_ENTRY NextCCB; + // each CCB is associated with a file object + PFILE_OBJECT PtrFileObject; + // flags (see below) associated with this CCB + uint32 CCBFlags; + // current byte offset is required sometimes + LARGE_INTEGER CurrentByteOffset; + // if this CCB represents a directory object open, we may + // need to maintain a search pattern + + // PSTRING DirectorySearchPattern; + UNICODE_STRING DirectorySearchPattern; + + // The full path name for the file... + UNICODE_STRING AbsolutePathName; + + // Rename/Link Target file name + // Used only in a Rename/Link operation + UNICODE_STRING RenameLinkTargetFileName; + + // we must maintain user specified file time values + uint32 UserSpecifiedTime; + + +} Ext2CCB, *PtrExt2CCB; + + +/************************************************************************** + the following CCBFlags values are relevant. These flag + values are bit fields; therefore we can test whether + a bit position is set (1) or not set (0). +**************************************************************************/ + +// some on-disk file/directories are opened by EXT2 itself +// as opposed to being opened on behalf of a user process +#define EXT2_CCB_OPENED_BY_EXT2 (0x00000001) +// the file object specified synchronous access at create/open time. +// this implies that EXT2 must maintain the current byte offset +#define EXT2_CCB_OPENED_FOR_SYNC_ACCESS (0x00000002) +// file object specified sequential access for this file +#define EXT2_CCB_OPENED_FOR_SEQ_ACCESS (0x00000004) +// the CCB has had an IRP_MJ_CLEANUP issued on it. we must +// no longer allow the file object / CCB to be used in I/O requests. +#define EXT2_CCB_CLEANED (0x00000008) +// if we were invoked via the fast i/o path to perform file i/o; +// we should set the CCB access/modification time at cleanup +#define EXT2_CCB_ACCESSED (0x00000010) +#define EXT2_CCB_MODIFIED (0x00000020) +// if an application process set the file date time, we must +// honor that request and *not* overwrite the values at cleanup +#define EXT2_CCB_ACCESS_TIME_SET (0x00000040) +#define EXT2_CCB_MODIFY_TIME_SET (0x00000080) +#define EXT2_CCB_CREATE_TIME_SET (0x00000100) + +#define EXT2_CCB_NOT_FROM_ZONE (0x80000000) + +// this CCB was allocated for a "volume open" operation +#define EXT2_CCB_VOLUME_OPEN (0x00000100) + +/************************************************************************** + each open file/directory/volume is represented by a file control block. + NOTE: Currently, EXT2 does not handle multiply linked files correctly. + In your FSD implementation, you must be careful about handling + such on-disk files correctly i.e. a single (unique) FCB must + represent an on-disk file/directory regardless of the path used + to access the on-disk object. + With the current EXT2 implementation, an on-disk file object + with more than a single (hard) link will be treated incorrectly! + + Each FCB can logically be divided into two: + (a) a structure that must have a field of type FSRTL_COMMON_FCB_HEADER + as the first field in the structure. + This portion should also contain other structures/resources required + by the NT Cache Manager + We will call this structure the "NT Required" FCB. Note that this + portion of the FCB must be allocated from non-paged pool. + (b) the remainder of the FCB is dependent upon the particular FSD + requirements. + This portion of the FCB could possibly be allocated from paged + memory, though in the sample FSD, it will always be allocated + from non-paged pool. + + FCB structures are protected by the MainResource as well as the + PagingIoResource. Of course, if your FSD implementation requires + it, you can associate other syncronization structures with the + FCB. + + This structure must be quad-word aligned because it is zone allocated. +**************************************************************************/ +typedef struct _Ext2NTRequiredFCB +{ + FSRTL_COMMON_FCB_HEADER CommonFCBHeader; + SECTION_OBJECT_POINTERS SectionObject; + ERESOURCE MainResource; + ERESOURCE PagingIoResource; +} Ext2NTRequiredFCB, *PtrExt2NTRequiredFCB; + +typedef struct _Ext2DiskDependentFCB +{ + // although the sample FSD does not maintain on-disk data structures, + // this structure serves as a reminder of the logical separation that + // your FSD can maintain between the disk dependent and the disk + // independent portions of the FCB. + uint16 DummyField; // placeholder +} Ext2DiskDependentFCB, *PtrExt2DiskDependentFCB; + +typedef struct _Ext2FileControlBlock +{ + Ext2Identifier NodeIdentifier; + // we will go ahead and embed the "NT Required FCB" right here. + // Note though that it is just as acceptable to simply allocate + // memory separately for the other half of the FCB and store a + // pointer to the "NT Required" portion here instead of embedding + // it ... + Ext2NTRequiredFCB NTRequiredFCB; + // the disk dependent portion of the FCB is embedded right here + Ext2DiskDependentFCB DiskDependentFCB; + // this FCB belongs to some mounted logical volume + struct _Ext2VolumeControlBlock *PtrVCB; + // to be able to access all open file(s) for a volume, we will + // link all FCB structures for a logical volume together + LIST_ENTRY NextFCB; + + // to be used if this FCB is on the Closable FCB List... + struct _ClosableFCBs + { + LIST_ENTRY ClosableFCBList; + BOOLEAN OnClosableFCBList; + }ClosableFCBs; + + // some state information for the FCB is maintained using the + // flags field + uint32 FCBFlags; + // all CCB's for this particular FCB are linked off the following + // list head. + LIST_ENTRY CCBListHead; + // NT requires that a file system maintain and honor the various + // SHARE_ACCESS modes ... + SHARE_ACCESS FCBShareAccess; + // to identify the lazy writer thread(s) we will grab and store + // the thread id here when a request to acquire resource(s) + // arrives .. + uint32 LazyWriterThreadID; + // whenever a file stream has a create/open operation performed, + // the Reference count below is incremented AND the OpenHandle count + // below is also incremented. + // When an IRP_MJ_CLEANUP is received, the OpenHandle count below + // is decremented. + // When an IRP_MJ_CLOSE is received, the Reference count below is + // decremented. + // When the Reference count goes down to zero, the FCB can be de-allocated. + // Note that a zero Reference count implies a zero OpenHandle count. + // This invariant must always hold true ... (if it is really an invariant, + // shoudn't the previous statement be redundant ... hmmm!!!) + LONG ReferenceCount; + LONG OpenHandleCount; + // for the sample fsd, there exists a 1-1 correspondence between an + // object name structure and a FCB + PtrExt2ObjectName FCBName; + // we will maintain some time information here to make our life easier + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + // Byte-range file lock support (we roll our own) + Ext2FileLockAnchor FCBByteRangeLock; + // The OPLOCK support package requires the following structure + OPLOCK FCBOplock; + + // The I-Node no of this file / folder + ULONG INodeNo; + ULONG ParentINodeNo; + // Pointers to blocks + uint32 IBlock[EXT2_N_BLOCKS]; + + USHORT LinkCount; + union _DCBFCB + { + struct + { + PFILE_OBJECT PtrDirFileObject; + } Dcb; + + struct _FCB + { + PFILE_OBJECT PtrDirFileObject; + // FCB specific stuff go here... + } Fcb; + + }DcbFcb; + +} Ext2FCB, *PtrExt2FCB, Ext2DCB, *PtrExt2DCB; + +/************************************************************************** + the following FCBFlags values are relevant. These flag + values are bit fields; therefore we can test whether + a bit position is set (1) or not set (0). +**************************************************************************/ +#define EXT2_FCB_IN_INIT (0x00000001) +#define EXT2_FCB_IN_TEARDOWN (0x00000002) +#define EXT2_FCB_PAGE_FILE (0x00000004) +#define EXT2_FCB_DIRECTORY (0x00000008) +#define EXT2_FCB_ROOT_DIRECTORY (0x00000018) +#define EXT2_FCB_WRITE_THROUGH (0x00000020) +#define EXT2_FCB_MAPPED (0x00000040) +#define EXT2_FCB_FAST_IO_READ_IN_PROGESS (0x00000080) +#define EXT2_FCB_FAST_IO_WRITE_IN_PROGESS (0x00000100) +#define EXT2_FCB_DELETE_ON_CLOSE (0x00000200) +#define EXT2_FCB_MODIFIED (0x00000400) +#define EXT2_FCB_ACCESSED (0x00000800) +#define EXT2_FCB_READ_ONLY (0x00001000) + +#define EXT2_INITIALIZED_MAIN_RESOURCE (0x00002000) +#define EXT2_INITIALIZED_PAGING_IO_RESOURCE (0x00004000) +#define EXT2_FCB_BLOCKS_INITIALIZED (0x00008000) +#define EXT2_FCB_SPECIAL_FILE (0x00010000) +#define EXT2_FCB_HIDDEN_FILE (0x00020000) +#define EXT2_FCB_NOT_FROM_ZONE (0x80000000) + + +typedef struct _GroupDescriptors +{ + uint32 InodeTablesBlock; /* Inodes table block => bg_inode_table */ + uint32 InodeBitmapBlock; /* Inodes bitmap block => bg_inode_bitmap */ + uint32 BlockBitmapBlock; /* Blocks bitmap block => bg_block_bitmap */ + uint32 FreeBlocksCount; + uint32 FreeInodesCount; +}Ext2GroupDescriptors, *PtrExt2GroupDescriptors; + + + +/************************************************************************** + A logical volume is represented using the following structure. + This structure is allocated as part of the device extension + for a device object that this sample FSD will create, to represent + the mounted logical volume. + + NOTE: If you were to extend this sample FSD to be a "real" FSD, + you would be worried about allocated clusters/sectiors, + bitmaps providing such information for the mounted volume, + dirty/modified clusters/sectiors etc. + This sample FSD does not maintain such information in the + in-memory VCB, though you may wish to consider it. +**************************************************************************/ +typedef struct _Ext2VolumeControlBlock +{ + Ext2Identifier NodeIdentifier; + + // Required to use the Cache Manager. + FSRTL_COMMON_FCB_HEADER CommonVCBHeader; + SECTION_OBJECT_POINTERS SectionObject; + // a resource to protect the fields contained within the VCB + ERESOURCE VCBResource; + + // a resource to synchronise paging io + ERESOURCE PagingIoResource; + + // Pointer to a stream file object created for the volume information + // to be more easily read from secondary storage (with the support of + // the NT Cache Manager). + PFILE_OBJECT PtrStreamFileObject; + + // each VCB is accessible off a global linked list + LIST_ENTRY NextVCB; + + // each VCB points to a VPB structure created by the NT I/O Manager + PVPB PtrVPB; + + // a set of flags that might mean something useful + uint32 VCBFlags; + + // A count of the number of open files/directories + // As long as the count is != 0, the volume cannot + // be dismounted or locked. + uint32 VCBOpenCount; + + // a global list of all FCB structures associated with the VCB + LIST_ENTRY FCBListHead; + + // + // a list of FCBs created at the FSD's initiative... + // These FCBs have a reference count of 0 + // This list should never be allowed to cross a limit... + // + struct Ext2ClosableFCB + { + LIST_ENTRY ClosableFCBListHead; + ULONG Count; + }ClosableFCBs; + // we will maintain a global list of IRP's that are pending + // because of a directory notify request. + LIST_ENTRY NextNotifyIRP; + // the above list is protected only by the mutex declared below + KMUTEX NotifyIRPMutex; + // for each mounted volume, we create a device object. Here then + // is a back pointer to that device object + PDEVICE_OBJECT VCBDeviceObject; + // We also retain a pointer to the physical device object on which we + // have mounted ourselves. The I/O Manager passes us a pointer to this + // device object when requesting a mount operation. + PDEVICE_OBJECT TargetDeviceObject; + // the volume structure contains a pointer to the root directory FCB + PtrExt2FCB PtrRootDirectoryFCB; + // the complete name of the user visible drive letter we serve + uint8 *PtrVolumePath; + // For volume open operations, we do not create a FCB (we use the VCB + // directly instead). Therefore, all CCB structures for the volume + // open operation are linked directly off the VCB + LIST_ENTRY VolumeOpenListHead; + + + // Volume information + ULONG BlocksCount; + ULONG InodesCount; + ULONG ReservedBlocksCount; + ULONG FreeBlocksCount; + ULONG FreeInodesCount; + ULONG LogBlockSize; // Block size = 1024 << LogBlockSize + + // Group Information Saved up in the VCB... + PtrExt2GroupDescriptors PtrGroupDescriptors; + ULONG NoOfGroups; + + uint32 InodesPerGroup; + uint32 BlocksPerGroup; + +} Ext2VCB, *PtrExt2VCB; + +// some valid flags for the VCB +#define EXT2_VCB_FLAGS_VOLUME_MOUNTED (0x00000001) +#define EXT2_VCB_FLAGS_VOLUME_LOCKED (0x00000002) +#define EXT2_VCB_FLAGS_BEING_DISMOUNTED (0x00000004) +#define EXT2_VCB_FLAGS_SHUTDOWN (0x00000008) +#define EXT2_VCB_FLAGS_VOLUME_READ_ONLY (0x00000010) + +#define EXT2_VCB_FLAGS_VCB_INITIALIZED (0x00000020) + +typedef struct _EXT2_IO_CONTEXT +{ + Ext2Identifier NodeIdentifier; + ULONG ReadWriteLength; + LONG Count; + PIRP PtrMasterIrp; + PKEVENT PtrSyncEvent; + +} EXT2_IO_CONTEXT, *PEXT2_IO_CONTEXT; + + +typedef struct _Ext2SavedBCBs +{ + Ext2Identifier NodeIdentifier; + PBCB PtrBCB; + LIST_ENTRY SavedBCBsListEntry; + +} EXT2_SAVED_BCBS, *PEXT2_SAVED_BCBS; + + +/************************************************************************** + The IRP context encapsulates the current request. This structure is + used in the "common" dispatch routines invoked either directly in + the context of the original requestor, or indirectly in the context + of a system worker thread. +**************************************************************************/ +typedef struct _Ext2IrpContext +{ + Ext2Identifier NodeIdentifier; + uint32 IrpContextFlags; + // copied from the IRP + uint8 MajorFunction; + // copied from the IRP + uint8 MinorFunction; + + // to queue this IRP for asynchronous processing + WORK_QUEUE_ITEM WorkQueueItem; + // the IRP for which this context structure was created + PIRP Irp; + // the target of the request (obtained from the IRP) + PDEVICE_OBJECT TargetDeviceObject; + // if an exception occurs, we will store the code here + NTSTATUS SavedExceptionCode; + + // This list entry is used if asnchronous processing is required... + LIST_ENTRY ThreadQueueListEntry; + + // This list entry is used if BCBs are to be saved and then flushed... + // Could have been put somewhere else... + LIST_ENTRY SavedBCBsListHead; + ULONG SavedCount; + +} Ext2IrpContext, *PtrExt2IrpContext; + +#define EXT2_IRP_CONTEXT_CAN_BLOCK (0x00000001) +#define EXT2_IRP_CONTEXT_WRITE_THROUGH (0x00000002) +#define EXT2_IRP_CONTEXT_EXCEPTION (0x00000004) +#define EXT2_IRP_CONTEXT_DEFERRED_WRITE (0x00000008) +#define EXT2_IRP_CONTEXT_ASYNC_PROCESSING (0x00000010) +#define EXT2_IRP_CONTEXT_NOT_TOP_LEVEL (0x00000020) + +#define EXT2_IRP_CONTEXT_NOT_FROM_ZONE (0x80000000) + +typedef struct _Ext2ThreadQueue +{ + HANDLE QueueHandlerThread; + + LIST_ENTRY ThreadQueueListHead; // This holds the Contexts + // that are to be scheduled + KSPIN_LOCK SpinLock; // To synchronize access to + // the list + KEVENT QueueEvent; // The Worker thread queue + // package waits on this event +} Ext2ThreadQueue; + +/************************************************************************** + we will store all of our global variables in one structure. + Global variables are not specific to any mounted volume BUT + by definition are required for successful operation of the + FSD implementation. +**************************************************************************/ +typedef struct _Ext2Data +{ + Ext2Identifier NodeIdentifier; + // the fields in this list are protected by the following resource + ERESOURCE GlobalDataResource; + // each driver has a driver object created for it by the NT I/O Mgr. + // we are no exception to this rule. + PDRIVER_OBJECT Ext2DriverObject; + // we will create a device object for our FSD as well ... + // Although not really required, it helps if a helper application + // writen by us wishes to send us control information via + // IOCTL requests ... + PDEVICE_OBJECT Ext2DeviceObject; + // we will keep a list of all logical volumes for our sample FSD + LIST_ENTRY NextVCB; + // the NT Cache Manager, the I/O Manager and we will conspire + // to bypass IRP usage using the function pointers contained + // in the following structure + FAST_IO_DISPATCH Ext2FastIoDispatch; + // The NT Cache Manager uses the following call backs to ensure + // correct locking hierarchy is maintained + CACHE_MANAGER_CALLBACKS CacheMgrCallBacks; + // structures allocated from a zone need some fields here. Note + // that under version 4.0, it might be better to use lookaside + // lists + KSPIN_LOCK ZoneAllocationSpinLock; + ZONE_HEADER ObjectNameZoneHeader; + ZONE_HEADER CCBZoneHeader; + ZONE_HEADER FCBZoneHeader; + ZONE_HEADER ByteLockZoneHeader; + ZONE_HEADER IrpContextZoneHeader; + void *ObjectNameZone; + void *CCBZone; + void *FCBZone; + void *ByteLockZone; + void *IrpContextZone; + + // currently, there is a single default zone size value used for + // all zones. This should ideally be changed by you to be 1 per + // type of zone (e.g. a default size for the FCB zone might be + // different from the default size for the ByteLock zone). + + // Of course, you will need to use different values (min/max) + // for lookaside lists (if you decide to use them instead) + uint32 DefaultZoneSizeInNumStructs; + + // some state information is maintained in the flags field + uint32 Ext2Flags; + + // Handle returned by the MUP is stored here. + HANDLE MupHandle; + + // Time difference + LARGE_INTEGER TimeDiff; + + // The Worker Thread package uses this structure... + Ext2ThreadQueue ThreadQueue; + +}Ext2Data, *PtrExt2Data; + +// valid flag values for the global data structure +#define EXT2_DATA_FLAGS_RESOURCE_INITIALIZED (0x00000001) +#define EXT2_DATA_FLAGS_ZONES_INITIALIZED (0x00000002) + +// a default size of the number of pages of non-paged pool allocated +// for each of the zones ... + +// Note that the values are absolutely arbitrary, the only information +// worth using from the values themselves is that they increase for +// larger systems (i.e. systems with more memory) +#define EXT2_DEFAULT_ZONE_SIZE_SMALL_SYSTEM (0x4) +#define EXT2_DEFAULT_ZONE_SIZE_MEDIUM_SYSTEM (0x8) +#define EXT2_DEFAULT_ZONE_SIZE_LARGE_SYSTEM (0xc) + +// another simplistic (brain dead ? :-) method used is to simply double +// the values for a "server" machine + +// So, for all you guys who "modified" the registry ;-) to change the +// wkstation into a server, tough luck ! +#define EXT2_NTAS_MULTIPLE (0x2) + +/*************************************************************************** +The following locking hierarchy is maintained in this sample filesystem +driver: + +(a) the global structure resource can be acquired at any time. However, + it is an "end resource" i.e. once acquired, no other resource can + be obtained until the global structure resource is released. +(b) the logical volume resource must be acquired (if required) before + any of the other resources are acquired. +(c) a file control block can be acquired next (if required). If two + FCB structures need to be acquired, the FCB "higher" in the directory + tree must be acquired first. + For a FCB, the "main resource" must be acquired first before a + "paging i/o" resource is acquired. + +Whenever a file is opened, the logical volume structure is referenced. +This ensures that the volume cannot be dismounted while any file is open. + +***************************************************************************/ + +typedef struct _IO_RUN +{ + UINT LogicalBlock; + UINT StartOffset; + UINT EndOffset; + PIRP PtrAssociatedIrp; + +} EXT2_IO_RUN, *PEXT2_IO_RUN; + +typedef struct _SIBlocks +{ + PBCB PtrBCB; + ULONG * PtrSIBlocks; +} EXT2_SIBLOCKS, *PEXT2_SIBLOCKS; + +#endif // has this file been included? + diff --git a/reactos/drivers/filesystems/ext2/src/DiskIO.c b/reactos/drivers/filesystems/ext2/src/DiskIO.c new file mode 100644 index 00000000000..81ca894f8e4 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/DiskIO.c @@ -0,0 +1,215 @@ +/************************************************************************* +* +* File: DiskIO.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Should contain code to handle Disk IO. +* +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +#define EXT2_BUG_CHECK_ID EXT2_FILE_DISK_IO + +#define DEBUG_LEVEL ( DEBUG_TRACE_DISKIO ) + + +/************************************************************************* +* +* Function: Ext2ReadLogicalBlocks() +* +* Description: +* The higherlevel functions will use this to read in logical blocks +* This function deals with the logical to physical block translation +* +* LogicalBlock - This is a 1 based index. +* That is, the first block is Block 1 +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: The Status of the Read IO +* +*************************************************************************/ +NTSTATUS Ext2ReadLogicalBlocks ( + PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object + VOID *Buffer, // The Buffer that takes the data read in + LARGE_INTEGER StartLogicalBlock, // The logical block from which reading is to start + unsigned int NoOfLogicalBlocks // The no. of logical blocks to be read + ) +{ + // The Status to be returned... + NTSTATUS Status = STATUS_SUCCESS; + + // The Device Object representing the mounted volume + PDEVICE_OBJECT PtrVolumeDeviceObject = NULL; + + // Volume Control Block + PtrExt2VCB PtrVCB = NULL; + + // Logical Block Size + ULONG LogicalBlockSize; + + // Physical Block Size + ULONG PhysicalBlockSize; + + // The starting Physical Block No... + LARGE_INTEGER StartPhysicalBlock; + + unsigned int NoOfPhysicalBlocks; + + + + // Done with declerations... + // Now for some code ;) + + // Getting the Logical and Physical Sector sizes + PtrVolumeDeviceObject = PtrTargetDeviceObject->Vpb->DeviceObject; + ASSERT( PtrVolumeDeviceObject ); + PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); + ASSERT(PtrVCB); + ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + PhysicalBlockSize = PtrTargetDeviceObject->SectorSize; + + NoOfPhysicalBlocks = NoOfLogicalBlocks * LogicalBlockSize / PhysicalBlockSize; + + StartPhysicalBlock.QuadPart = ( StartLogicalBlock.QuadPart ) * + ( LogicalBlockSize / PhysicalBlockSize ); + + Status = Ext2ReadPhysicalBlocks( PtrTargetDeviceObject, + Buffer, StartPhysicalBlock, NoOfPhysicalBlocks ); + + return Status; +} + +/************************************************************************* +* +* Function: Ext2ReadPhysicalBlocks() +* +* Description: +* The higherlevel functions will use this to read in physical blocks +* +* PhysicalBlock - This is a 0 based number. +* That is, the first block is Block 0 +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: The Status of the Read IO +* +*************************************************************************/ +NTSTATUS Ext2ReadPhysicalBlocks ( + PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object + VOID *Buffer, // The Buffer that takes the data read in + LARGE_INTEGER StartPhysicalBlock, // The block from which reading is to start + unsigned int NoOfBlocks // The no. of blocks to be read + ) +{ + // The Status to be returned... + NTSTATUS Status = STATUS_SUCCESS; + + // Physical Block Size + ULONG PhysicalBlockSize; + + // No of bytes to read + ULONG NumberOfBytesToRead; + + // Synchronisation Event + KEVENT Event; + + // IRP + PIRP Irp; + + // Status Block + IO_STATUS_BLOCK Iosb; + + // Byte Offset + LARGE_INTEGER ByteOffset; + + // Done with declerations... + // Now for some code ;) + + // Getting the Physical Sector size + PhysicalBlockSize = PtrTargetDeviceObject->SectorSize; + + NumberOfBytesToRead = PhysicalBlockSize * NoOfBlocks; + + ByteOffset.QuadPart = StartPhysicalBlock.QuadPart * PhysicalBlockSize; + + try + { + // + // Initialize the event we're going to use + // + KeInitializeEvent( &Event, NotificationEvent, FALSE ); + + // + // Build the irp for the operation and also set the overrride flag + // + Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, + PtrTargetDeviceObject, + Buffer, + NumberOfBytesToRead, + &ByteOffset , + &Event, + &Iosb ); + + if ( Irp == NULL ) + { + DebugTrace(DEBUG_TRACE_MISC, " !!!! Unable to create an IRP", 0 ); + Status = STATUS_INSUFFICIENT_RESOURCES; + try_return( Status ); + } + + // + // Call the device to do the read and wait for it to finish. + // + Status = IoCallDriver( PtrTargetDeviceObject, Irp ); + + // + // Check if it is done already!!!! + // + if (Status == STATUS_PENDING) + { + // + // Read not done yet... + // Wait till it is... + // + (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + Status = Iosb.Status; + } + + try_exit: NOTHING; + } + finally + { + if (!NT_SUCCESS(Status)) + { + if( Status == STATUS_VERIFY_REQUIRED ) + { + DebugTrace(DEBUG_TRACE_MISC, " !!!! Verify Required! Failed to read disk",0 ); + } + else if (Status == STATUS_INVALID_PARAMETER) + { + DebugTrace(DEBUG_TRACE_MISC, " !!!! Invalid Parameter! Failed to read disk",0 ); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, " !!!! Failed to read disk! Status returned = %d", Status ); + } + } + } + return Status; +} + + diff --git a/reactos/drivers/filesystems/ext2/src/cleanup.c b/reactos/drivers/filesystems/ext2/src/cleanup.c new file mode 100644 index 00000000000..50a2ab07305 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/cleanup.c @@ -0,0 +1,400 @@ +/************************************************************************* +* +* File: cleanup.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Should contain code to handle the "Cleanup" dispatch entry point. +* This file serves as a placeholder. Please update this file as part +* of designing and implementing your FSD. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_CLEANUP +#define DEBUG_LEVEL (DEBUG_TRACE_CLEANUP) + + +/************************************************************************* +* +* Function: Ext2Cleanup() +* +* Description: +* The I/O Manager will invoke this routine to handle a cleanup +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS Ext2Cleanup( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Cleanup IRP Received...", 0); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonCleanup(PtrIrpContext, Irp, TRUE); + + } + except( Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation() ) ) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2CommonCleanup() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS Ext2CommonCleanup( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ) +{ + + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PERESOURCE PtrResourceAcquired = NULL; + IO_STATUS_BLOCK LocalIoStatus; + + BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + BOOLEAN AcquiredVCB = FALSE; + BOOLEAN CanWait = FALSE; + BOOLEAN BlockForResource; + int i = 1; + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + if( !PtrFileObject->FsContext2 ) + { + // This must be a Cleanup request received + // as a result of IoCreateStreamFileObject + // Only such a File object would have a NULL CCB + + DebugTrace( DEBUG_TRACE_MISC, " === Cleanup with NULL CCB", 0); + if( PtrFileObject ) + { + DebugTrace( DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + try_return( RC ); + } + + + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) + //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer ) + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); + } + else + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup Volume", 0); + } + + + PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(PtrVCB); + ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + // (a) Acquiring the VCBResource Exclusively... + // This is done to synchronise with the close and cleanup routines... + BlockForResource = !FirstAttempt; + if( !FirstAttempt ) + { + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire VCB Exclusively [Cleanup]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Cleanup]", 0); + } + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + + i = 1; + while( !AcquiredVCB ) + { + DebugTraceState("VCB AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + if( ! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) + { + DebugTrace( DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Cleanup]", 0); + if( BlockForResource && i != 1000 ) + { + LARGE_INTEGER Delay; + Delay.QuadPart = -500 * i; + KeDelayExecutionThread( KernelMode, FALSE, &Delay ); + DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i); + } + else + { + if( i == 1000 ) + DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 ); + PostRequest = TRUE; + try_return( RC = STATUS_PENDING ); + } + } + else + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired in [Cleanup]", 0); + AcquiredVCB = TRUE; + } + i *= 10; + } + + + // (b) Acquire the file (FCB) exclusively + if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) + { + // This FCB is an FCB indeed. ;) + // So acquiring it exclusively... + // This is done to synchronise with read/write routines... + if( !FirstAttempt ) + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire FCB Exclusively [Cleanup]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Cleanup]", 0); + } + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + + i = 1; + while( !PtrResourceAcquired ) + { + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Cleanup]", 0); + if( BlockForResource && i != 1000 ) + { + LARGE_INTEGER Delay; + Delay.QuadPart = -500 * i; + KeDelayExecutionThread( KernelMode, FALSE, &Delay ); + DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i); + } + else + { + if( i == 1000 ) + DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 ); + PostRequest = TRUE; + try_return( RC = STATUS_PENDING ); + } + } + else + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB acquired [Cleanup]", 0); + PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource ); + } + i *= 10; + } + + // (c) Flush file data to disk + if ( PtrFileObject->PrivateCacheMap != NULL) + { + IO_STATUS_BLOCK Status; + CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status ); + } + + // (d) Talk to the FSRTL package (if you use it) about pending oplocks. + // (e) Notify the FSRTL package (if you use it) for use with pending + // notification IRPs + // (f) Unlock byte-range locks (if any were acquired by process) + + // (g) Attempting to update time stamp values + // Errors are ignored... + // Not considered as critical errors... + + /* + if( PtrFCB->OpenHandleCount == 1 ) + { + ULONG CreationTime, AccessTime, ModificationTime; + EXT2_INODE Inode; + + CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + // Update time stamps in the inode... + Inode.i_ctime = CreationTime; + Inode.i_atime = AccessTime; + Inode.i_mtime = ModificationTime; + + // Updating the inode... + Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ); + } + } + */ + + // (h) Inform the Cache Manager to uninitialize Cache Maps ... + CcUninitializeCacheMap( PtrFileObject, NULL, NULL ); + + // (i) Decrementing the Open Handle count... + if( PtrFCB->OpenHandleCount ) + { + InterlockedDecrement( &PtrFCB->OpenHandleCount ); + } + else + { + Ext2BreakPoint(); + } + + PtrFCB->FCBFlags |= FO_CLEANUP_COMPLETE; + + DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Cleanup]", PtrFCB->ReferenceCount ); + DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Cleanup]", PtrFCB->OpenHandleCount ); + + // (j) Remove share access... + // Will do that later ;) + + // (k) Is this a close on delete file? + // If so, delete the file... + if( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE) && + !PtrFCB->OpenHandleCount ) + { + // + // Have to delete this file... + // + Ext2DeleteFile( PtrFCB, PtrIrpContext ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = 0; + PtrFCB->INodeNo = 0; + } + } + else + { + // This must be a volume close... + // Just go ahead and complete this IRP... + PtrVCB->VCBOpenCount--; + DebugTrace(DEBUG_TRACE_MISC, "VCB Cleanup Requested !!!", 0); + CompleteIrp = TRUE; + } + + try_return( RC ); + + try_exit: NOTHING; + + } + finally + { + if(PtrResourceAcquired) + { + Ext2ReleaseResource(PtrResourceAcquired); + DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** Resource Released [Cleanup]", 0); + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + + } + + if( AcquiredVCB ) + { + ASSERT(PtrVCB); + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** VCB Released [Cleanup]", 0); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + AcquiredVCB = FALSE; + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); + } + + } + + if( PostRequest ) + { + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + if( RC != STATUS_PENDING ) + { + Ext2ReleaseIrpContext( PtrIrpContext ); + // complete the IRP + IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT ); + } + } // end of "finally" processing + + return(RC); +} diff --git a/reactos/drivers/filesystems/ext2/src/close.c b/reactos/drivers/filesystems/ext2/src/close.c new file mode 100644 index 00000000000..8b83497b64d --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/close.c @@ -0,0 +1,459 @@ +/************************************************************************* +* +* File: close.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Should contain code to handle the "Close" dispatch entry point. +* This file serves as a placeholder. Please update this file as part +* of designing and implementing your FSD. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_CLOSE + +#define DEBUG_LEVEL (DEBUG_TRACE_CLOSE) + + +/************************************************************************* +* +* Function: Ext2Close() +* +* Description: +* The I/O Manager will invoke this routine to handle a close +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS Ext2Close( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Close IRP Received...", 0); + + + FsRtlEnterFileSystem(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonClose(PtrIrpContext, Irp, TRUE); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonClose() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Does not matter! +* +*************************************************************************/ +NTSTATUS Ext2CommonClose( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PERESOURCE PtrResourceAcquired = NULL; + IO_STATUS_BLOCK LocalIoStatus; + + BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + BOOLEAN AcquiredVCB = FALSE; + BOOLEAN CanWait = FALSE; + BOOLEAN BlockForResource; + int i = 1; + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + if( !PtrFileObject->FsContext2 ) + { + // This must be a Cleanup request received + // as a result of IoCreateStreamFileObject + // Only such a File object would have a NULL CCB + + DebugTrace( DEBUG_TRACE_SPECIAL, " === Close with NULL CCB", 0); + if( PtrFileObject ) + { + DebugTrace( DEBUG_TRACE_SPECIAL, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + Ext2BreakPoint(); + try_return( RC ); + } + + // Get the FCB and CCB pointers + + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT( PtrVCB ); + + if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) + //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer ) + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); + } + else + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -null-", 0); + } + + // (a) Acquiring the VCBResource Exclusively... + // This is done to synchronise with the close and cleanup routines... +// if( ExTryToAcquireResourceExclusiveLite(&(PtrVCB->VCBResource) ) ) + + BlockForResource = !FirstAttempt; + if( !FirstAttempt ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Close]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [Close]", 0); + } + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + i = 1; + while( !AcquiredVCB ) + { + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + if(! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [Close]", 0); + if( BlockForResource && i != 1000 ) + { + LARGE_INTEGER Delay; + + //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); + + Delay.QuadPart = -500 * i; + KeDelayExecutionThread( KernelMode, FALSE, &Delay ); + DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); + } + else + { + if( i == 1000 ) + DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); + PostRequest = TRUE; + try_return( RC = STATUS_PENDING ); + } + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in [Close]", 0); + AcquiredVCB = TRUE; + } + i *= 10; + } + + // (b) Acquire the file (FCB) exclusively + if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) + { + // This FCB is an FCB indeed. ;) + // So acquiring it exclusively... + // This is done to synchronise with read/write routines... + if( !FirstAttempt ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively [Close]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [Close]", 0); + } + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + i = 1; + while( !PtrResourceAcquired ) + { + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Close]", 0); + if( BlockForResource && i != 1000 ) + { + LARGE_INTEGER Delay; + + //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); + + Delay.QuadPart = -500 * i; + KeDelayExecutionThread( KernelMode, FALSE, &Delay ); + DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); + } + else + { + if( i == 1000 ) + DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); + PostRequest = TRUE; + try_return( RC = STATUS_PENDING ); + } + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [Close]", 0); + PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource ); + } + i *= 10; + } + + // (c) Delete the CCB structure (free memory) + RemoveEntryList( &PtrCCB->NextCCB ); + Ext2ReleaseCCB( PtrCCB ); + PtrFileObject->FsContext2 = NULL; + + // (d) Decrementing the Reference Count... + if( PtrFCB->ReferenceCount ) + { + InterlockedDecrement( &PtrFCB->ReferenceCount ); + } + else + { + Ext2BreakPoint(); + } + DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Close]", PtrFCB->ReferenceCount ); + DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Close]", PtrFCB->OpenHandleCount ); + if( PtrFCB->ReferenceCount == 0 ) + { + + // Attempting to update time stamp values + // Errors are ignored... + // Not considered as critical errors... + + { + ULONG CreationTime, AccessTime, ModificationTime; + EXT2_INODE Inode; + + CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + // Update time stamps in the inode... + Inode.i_ctime = CreationTime; + Inode.i_atime = AccessTime; + Inode.i_mtime = ModificationTime; + + // Updating the inode... + Ext2WriteInode( NULL, PtrVCB, PtrFCB->INodeNo, &Inode ); + } + } + + + if( PtrFCB->INodeNo == EXT2_ROOT_INO ) + { + // + // Root Directory FCB + // Preserve this + // FSD has a File Object for this FCB... + // + DebugTrace(DEBUG_TRACE_MISC, "^^^^^Root Directory FCB ; leaveing it alone[Close]", 0); + // Do nothing... + + } + else if( PtrFCB->DcbFcb.Dcb.PtrDirFileObject ) + { + // + // If this is a FCB created on the FSD's initiative + // Leave it alone + // + DebugTrace(DEBUG_TRACE_MISC, "^^^^^FCB Created on the FSD's initiative; leaveing it alone[Close]", 0); + if( !PtrFCB->ClosableFCBs.OnClosableFCBList ) + { + InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, + &PtrFCB->ClosableFCBs.ClosableFCBList ); + PtrVCB->ClosableFCBs.Count++; + + PtrFCB->ClosableFCBs.OnClosableFCBList = TRUE; + } + + if( PtrVCB->ClosableFCBs.Count > EXT2_MAXCLOSABLE_FCBS_UL ) + { + PtrExt2FCB PtrTempFCB = NULL; + // Checking if Closable FCBs are too many in number... + // Shouldn't block the + // Should do this asynchronously... + // Maybe later... + PLIST_ENTRY PtrEntry = NULL; + + PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead ); + + PtrTempFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList ); + if( Ext2CloseClosableFCB( PtrTempFCB ) ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Close]", PtrTempFCB ); + ExFreePool( PtrTempFCB ); + PtrVCB->ClosableFCBs.Count--; + } + else + { + // Put the FCB back in the list... + InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, + &PtrTempFCB->ClosableFCBs.ClosableFCBList ); + } + DebugTrace( DEBUG_TRACE_SPECIAL, "ClosableFCBs Count = %ld [Close]", PtrVCB->ClosableFCBs.Count ); + } + } + else + { + // Remove this FCB as well... + DebugTrace(DEBUG_TRACE_MISC, "^^^^^Deleting FCB [Close]", 0); + RemoveEntryList( &PtrFCB->NextFCB ); + + if ( PtrResourceAcquired ) + { + Ext2ReleaseResource(PtrResourceAcquired); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Close]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + PtrResourceAcquired = FALSE; + } + Ext2ReleaseFCB( PtrFCB ); + } + + } + CompleteIrp = TRUE; + } + else + { + // This must be a volume close... + // What do I do now? ;) + DebugTrace(DEBUG_TRACE_MISC, "VCB Close Requested !!!", 0); + CompleteIrp = TRUE; + } + try_return( RC ); + + try_exit: NOTHING; + + } + finally + { + if ( PtrResourceAcquired ) + { + Ext2ReleaseResource(PtrResourceAcquired); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Close]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + PtrResourceAcquired = FALSE; + } + + if (AcquiredVCB) + { + ASSERT(PtrVCB); + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Close]", 0); + + AcquiredVCB = FALSE; + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); + } + + } + + if( PostRequest ) + { + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + else if( CompleteIrp && RC != STATUS_PENDING ) + { + // complete the IRP + IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT ); + + Ext2ReleaseIrpContext( PtrIrpContext ); + } + + } // end of "finally" processing + + return(RC); +} diff --git a/reactos/drivers/filesystems/ext2/src/create.c b/reactos/drivers/filesystems/ext2/src/create.c new file mode 100644 index 00000000000..13fe4e13b49 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/create.c @@ -0,0 +1,1681 @@ +/************************************************************************* +* +* File: create.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Create"/"Open" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_CREATE + +#define DEBUG_LEVEL (DEBUG_TRACE_CREATE) + + +/************************************************************************* +* +* Function: Ext2Create() +* +* Description: +* The I/O Manager will invoke this routine to handle a create/open +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2Create( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Create Control IRP received...", 0); + + FsRtlEnterFileSystem(); + + // Ext2BreakPoint(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // sometimes, we may be called here with the device object representing + // the file system (instead of the device object created for a logical + // volume. In this case, there is not much we wish to do (this create + // typically will happen 'cause some process has to open the FSD device + // object so as to be able to send an IOCTL to the FSD) + + // All of the logical volume device objects we create have a device + // extension whereas the device object representing the FSD has no + // device extension. This seems like a good enough method to identify + // between the two device objects ... + if (DeviceObject->Size == (unsigned short)(sizeof(DEVICE_OBJECT))) + { + // this is an open of the FSD itself + DebugTrace( DEBUG_TRACE_MISC, " === Open for the FSD itself", 0); + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = FILE_OPENED; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return(RC); + } + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonCreate(PtrIrpContext, Irp, TRUE ); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2CommonCreate() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonCreate( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PIO_SECURITY_CONTEXT PtrSecurityContext = NULL; + PFILE_OBJECT PtrNewFileObject = NULL; + PFILE_OBJECT PtrRelatedFileObject = NULL; + uint32 AllocationSize = 0; // if we create a new file + PFILE_FULL_EA_INFORMATION PtrExtAttrBuffer = NULL; + unsigned long RequestedOptions = 0; + unsigned long RequestedDisposition = 0; + uint8 FileAttributes = 0; + unsigned short ShareAccess = 0; + unsigned long ExtAttrLength = 0; + ACCESS_MASK DesiredAccess; + + BOOLEAN DeferredProcessing = FALSE; + + PtrExt2VCB PtrVCB = NULL; + BOOLEAN AcquiredVCB = FALSE; + + BOOLEAN DirectoryOnlyRequested = FALSE; + BOOLEAN FileOnlyRequested = FALSE; + BOOLEAN NoBufferingSpecified = FALSE; + BOOLEAN WriteThroughRequested = FALSE; + BOOLEAN DeleteOnCloseSpecified = FALSE; + BOOLEAN NoExtAttrKnowledge = FALSE; + BOOLEAN CreateTreeConnection = FALSE; + BOOLEAN OpenByFileId = FALSE; + + BOOLEAN SequentialOnly = FALSE; + BOOLEAN RandomAccess = FALSE; + + // Are we dealing with a page file? + BOOLEAN PageFileManipulation = FALSE; + + // Is this open for a target directory (used in rename operations)? + BOOLEAN OpenTargetDirectory = FALSE; + + // Should we ignore case when attempting to locate the object? + BOOLEAN IgnoreCaseWhenChecking = FALSE; + + PtrExt2CCB PtrRelatedCCB = NULL, PtrNewCCB = NULL; + PtrExt2FCB PtrRelatedFCB = NULL, PtrNewFCB = NULL; + + unsigned long ReturnedInformation = -1; + + UNICODE_STRING TargetObjectName; + UNICODE_STRING RelatedObjectName; + + UNICODE_STRING AbsolutePathName; + UNICODE_STRING RenameLinkTargetFileName; + + LARGE_INTEGER FileAllocationSize, FileEndOfFile; + + + ASSERT(PtrIrpContext); + ASSERT(PtrIrp); + + try + { + + AbsolutePathName.Buffer = NULL; + AbsolutePathName.Length = AbsolutePathName.MaximumLength = 0; + + // Getting a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + // Can we block? + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK)) + { + // Asynchronous processing required... + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + DeferredProcessing = TRUE; + try_return(RC); + } + + // Obtaining the parameters specified by the user. + PtrNewFileObject = PtrIoStackLocation->FileObject; + TargetObjectName = PtrNewFileObject->FileName; + PtrRelatedFileObject = PtrNewFileObject->RelatedFileObject; + + if( PtrNewFileObject->FileName.Length && PtrNewFileObject->FileName.Buffer ) + { + if( PtrNewFileObject->FileName.Buffer[ PtrNewFileObject->FileName.Length/2 ] != 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrFileObject->FileName not NULL terminated! [Create]", 0 ); + } + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -%S- [Create]", PtrNewFileObject->FileName.Buffer ); + } + else + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -null- [Create]", 0); + } + + // Is this a Relative Create/Open? + if (PtrRelatedFileObject) + { + PtrRelatedCCB = (PtrExt2CCB)(PtrRelatedFileObject->FsContext2); + ASSERT(PtrRelatedCCB); + ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); + // each CCB in turn points to a FCB + PtrRelatedFCB = PtrRelatedCCB->PtrFCB; + ASSERT(PtrRelatedFCB); + if( PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB && + PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB ) + { + // How the hell can this happen!!! + Ext2BreakPoint(); + } + + AssertFCBorVCB( PtrRelatedFCB ); + + RelatedObjectName = PtrRelatedFileObject->FileName; + + if( PtrRelatedFileObject->FileName.Length && PtrRelatedFileObject->FileName.Buffer ) + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -%S-", PtrRelatedFileObject->FileName.Buffer ); + } + else + { + DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -null-",0); + } + + } + + + AllocationSize = PtrIrp->Overlay.AllocationSize.LowPart; + // Only 32 bit file sizes supported... + + if (PtrIrp->Overlay.AllocationSize.HighPart) + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // Getting a pointer to the supplied security context + PtrSecurityContext = PtrIoStackLocation->Parameters.Create.SecurityContext; + + // Obtaining the desired access + DesiredAccess = PtrSecurityContext->DesiredAccess; + + // Getting the options supplied by the user... + RequestedOptions = (PtrIoStackLocation->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS); + RequestedDisposition = ((PtrIoStackLocation->Parameters.Create.Options >> 24) & 0xFF); + + FileAttributes = (uint8)(PtrIoStackLocation->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS); + ShareAccess = PtrIoStackLocation->Parameters.Create.ShareAccess; + PtrExtAttrBuffer = PtrIrp->AssociatedIrp.SystemBuffer; + + ExtAttrLength = PtrIoStackLocation->Parameters.Create.EaLength; + + SequentialOnly = ((RequestedOptions & FILE_SEQUENTIAL_ONLY ) ? TRUE : FALSE); + RandomAccess = ((RequestedOptions & FILE_RANDOM_ACCESS ) ? TRUE : FALSE); + + + DirectoryOnlyRequested = ((RequestedOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE); + FileOnlyRequested = ((RequestedOptions & FILE_NON_DIRECTORY_FILE) ? TRUE : FALSE); + NoBufferingSpecified = ((RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING) ? TRUE : FALSE); + WriteThroughRequested = ((RequestedOptions & FILE_WRITE_THROUGH) ? TRUE : FALSE); + DeleteOnCloseSpecified = ((RequestedOptions & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE); + NoExtAttrKnowledge = ((RequestedOptions & FILE_NO_EA_KNOWLEDGE) ? TRUE : FALSE); + CreateTreeConnection = ((RequestedOptions & FILE_CREATE_TREE_CONNECTION) ? TRUE : FALSE); + OpenByFileId = ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? TRUE : FALSE); + PageFileManipulation = ((PtrIoStackLocation->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE); + OpenTargetDirectory = ((PtrIoStackLocation->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE); + IgnoreCaseWhenChecking = ((PtrIoStackLocation->Flags & SL_CASE_SENSITIVE) ? TRUE : FALSE); + + // Ensure that the operation has been directed to a valid VCB ... + PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); + ASSERT(PtrVCB); + ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + + if( !PtrNewFileObject->Vpb ) + { + PtrNewFileObject->Vpb = PtrVCB->PtrVPB; + } + + // Acquiring the VCBResource Exclusively... + // This is done to synchronise with the close and cleanup routines... + + DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Create]", 0); + + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Create]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE); + + AcquiredVCB = TRUE; + + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in Create", 0); + if( PtrNewFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Create]", PtrNewFileObject); + } + + // Verify Volume... + // if (!NT_SUCCESS(RC = Ext2VerifyVolume(PtrVCB))) + // { + // try_return(RC); + // } + + // If the volume has been locked, fail the request + + if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_LOCKED) + { + DebugTrace(DEBUG_TRACE_MISC, "Volume locked. Failing Create", 0 ); + RC = STATUS_ACCESS_DENIED; + try_return(RC); + } + + + if ((PtrNewFileObject->FileName.Length == 0) && ((PtrRelatedFileObject == NULL) || + (PtrRelatedFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB))) + { + // + // >>>>>>>>>>>>> Volume Open requested. <<<<<<<<<<<<< + // + + // Performing validity checks... + if ((OpenTargetDirectory) || (PtrExtAttrBuffer)) + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + if (DirectoryOnlyRequested) + { + // a volume is not a directory + RC = STATUS_NOT_A_DIRECTORY; + try_return(RC); + } + + if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) + { + // cannot create a new volume, I'm afraid ... + RC = STATUS_ACCESS_DENIED; + try_return(RC); + } + DebugTrace(DEBUG_TRACE_MISC, "Volume open requested", 0 ); + RC = Ext2OpenVolume(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject); + ReturnedInformation = PtrIrp->IoStatus.Information; + + try_return(RC); + } + + if (OpenByFileId) + { + DebugTrace(DEBUG_TRACE_MISC, "Open by File Id requested", 0 ); + RC = STATUS_ACCESS_DENIED; + try_return(RC); + } + + // Relative path name specified... + if (PtrRelatedFileObject) + { + + if (!(PtrRelatedFCB->FCBFlags & EXT2_FCB_DIRECTORY)) + { + // we must have a directory as the "related" object + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // Performing validity checks... + if ((RelatedObjectName.Length == 0) || (RelatedObjectName.Buffer[0] != L'\\')) + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + if ((TargetObjectName.Length != 0) && (TargetObjectName.Buffer[0] == L'\\')) + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // Creating an absolute path-name. + { + AbsolutePathName.MaximumLength = TargetObjectName.Length + RelatedObjectName.Length + sizeof(WCHAR); + if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength); + + RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(RelatedObjectName.Buffer), RelatedObjectName.Length); + AbsolutePathName.Length = RelatedObjectName.Length; + RtlAppendUnicodeToString(&AbsolutePathName, L"\\"); + RtlAppendUnicodeToString(&AbsolutePathName, TargetObjectName.Buffer); + } + + } + // Absolute Path name specified... + else + { + + + // Validity Checks... + if (TargetObjectName.Buffer[0] != L'\\') + { + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + { + AbsolutePathName.MaximumLength = TargetObjectName.Length; + if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength); + + RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(TargetObjectName.Buffer), TargetObjectName.Length); + AbsolutePathName.Length = TargetObjectName.Length; + } + } + + + // Parsing the path... + if (AbsolutePathName.Length == 2) + { + + // this is an open of the root directory, ensure that the caller has not requested a file only + if (FileOnlyRequested || (RequestedDisposition == FILE_SUPERSEDE) || (RequestedDisposition == FILE_OVERWRITE) || + (RequestedDisposition == FILE_OVERWRITE_IF)) + { + RC = STATUS_FILE_IS_A_DIRECTORY; + try_return(RC); + } + + RC = Ext2OpenRootDirectory(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject); + DebugTrace(DEBUG_TRACE_MISC, " === Root directory opened", 0 ); + try_return(RC); + } + + + { + // Used during parsing the file path... + UNICODE_STRING RemainingName; + UNICODE_STRING CurrentName; + UNICODE_STRING NextRemainingName; + PEXT2_INODE PtrNextInode = NULL; + ULONG CurrInodeNo = 0; + PtrExt2FCB PtrCurrFCB = NULL; + PtrExt2FCB PtrNextFCB = NULL; + PFILE_OBJECT PtrCurrFileObject = NULL; + UINT NameBufferIndex; + ULONG Type = 0; + LARGE_INTEGER ZeroSize; + BOOLEAN Found = FALSE; + + ZeroSize.QuadPart = 0; + if ( PtrRelatedFileObject ) + { + CurrInodeNo = PtrRelatedFCB->INodeNo; + PtrCurrFCB = PtrRelatedFCB; + } + else + { + CurrInodeNo = PtrVCB->PtrRootDirectoryFCB->INodeNo; + PtrCurrFCB = PtrVCB->PtrRootDirectoryFCB; + + } + + // Ext2ZerooutUnicodeString( &RemainingName ); + Ext2ZerooutUnicodeString( &CurrentName ); + Ext2ZerooutUnicodeString( &NextRemainingName ); + + RemainingName = TargetObjectName; + + while ( !Found && CurrInodeNo ) + { + FsRtlDissectName ( RemainingName, &CurrentName, &NextRemainingName ); + + RemainingName = NextRemainingName; + // CurrInodeNo is the parent inode for the entry I am searching for + // PtrCurrFCB is the parent's FCB + // Current Name is its name... + + + PtrNextFCB = Ext2LocateChildFCBInCore ( PtrVCB, &CurrentName, CurrInodeNo ); + + if( PtrNextFCB ) + { + CurrInodeNo = PtrNextFCB->INodeNo; + + if( NextRemainingName.Length == 0 ) + { + // + // Done Parsing... + // Found the file... + // + Found = TRUE; + + if( OpenTargetDirectory ) + { + int i; + // + // This is for a rename/move operation... + // + ReturnedInformation = FILE_EXISTS; + + // Now replace the file name field with that of the + // Target file name... + Ext2CopyUnicodeString( + &RenameLinkTargetFileName, + &CurrentName ); + /* + + for( i = 0; i < (CurrentName.Length/2); i++ ) + { + PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i]; + } + PtrNewFileObject->FileName.Length = CurrentName.Length; + */ + // Now open the Parent Directory... + PtrNextFCB = PtrCurrFCB; + CurrInodeNo = PtrNextFCB->INodeNo; + } + + // + // Relating the FCB to the New File Object + // + PtrNewFileObject->Vpb = PtrVCB->PtrVPB; + PtrNewFileObject->PrivateCacheMap = NULL; + PtrNewFileObject->FsContext = (void *)( &(PtrNextFCB->NTRequiredFCB.CommonFCBHeader) ); + PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject) ; + break; + } + + else if( !Ext2IsFlagOn( PtrNextFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + // Invalid path... + // Can have only a directory in the middle of the path... + // + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return( RC ); + } + } + else // searching on the disk... + { + CurrInodeNo = Ext2LocateFileInDisk( PtrVCB, &CurrentName, PtrCurrFCB, &Type ); + if( !CurrInodeNo ) + { + // + // Not found... + // Quit searching... + // + + if( ( NextRemainingName.Length == 0 ) && + ( RequestedDisposition == FILE_CREATE ) || + ( RequestedDisposition == FILE_OPEN_IF) || + ( RequestedDisposition == FILE_OVERWRITE_IF) ) + + { + // + // Just the last component was not found... + // A create was requested... + // + if( DirectoryOnlyRequested ) + { + Type = EXT2_FT_DIR; + } + else + { + Type = EXT2_FT_REG_FILE; + } + + CurrInodeNo = Ext2CreateFile( PtrIrpContext, PtrVCB, + &CurrentName, PtrCurrFCB, Type ); + + if( !CurrInodeNo ) + { + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return( RC ); + } + // Set the allocation size for the object is specified + //IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess)); + // RC = STATUS_SUCCESS; + ReturnedInformation = FILE_CREATED; + + // Should also create a CCB structure... + // Doing that a little fathre down... ;) + + } + else if( NextRemainingName.Length == 0 && OpenTargetDirectory ) + { + int i; + // + // This is for a rename/move operation... + // Just the last component was not found... + // + ReturnedInformation = FILE_DOES_NOT_EXIST; + + // Now replace the file name field with that of the + // Target file name... + Ext2CopyUnicodeString( + &RenameLinkTargetFileName, + &CurrentName ); + /* + for( i = 0; i < (CurrentName.Length/2); i++ ) + { + PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i]; + } + PtrNewFileObject->FileName.Length = CurrentName.Length; + */ + + // Now open the Parent Directory... + PtrNextFCB = PtrCurrFCB; + CurrInodeNo = PtrNextFCB->INodeNo; + // Initialize the FsContext + PtrNewFileObject->FsContext = &PtrNextFCB->NTRequiredFCB.CommonFCBHeader; + // Initialize the section object pointer... + PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject); + PtrNewFileObject->Vpb = PtrVCB->PtrVPB; + PtrNewFileObject->PrivateCacheMap = NULL; + + break; + } + else + { + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return( RC ); + } + } + + if( NextRemainingName.Length ) + { + // Should be a directory... + if( Type != EXT2_FT_DIR ) + { + // Invalid path... + // Can have only a directory in the middle of the path... + // + RC = STATUS_OBJECT_PATH_NOT_FOUND; + try_return( RC ); + } + + PtrCurrFileObject = NULL; + } + else + { + // + // Done Parsing... + // Found the file... + // + Found = TRUE; + + // + // Was I supposed to create a new file? + // + if (RequestedDisposition == FILE_CREATE && + ReturnedInformation != FILE_CREATED ) + { + ReturnedInformation = FILE_EXISTS; + RC = STATUS_OBJECT_NAME_COLLISION; + try_return(RC); + } + + // Is this the type of file I was looking for? + // Do some checking here... + + if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE ) + { + // Deny access! + // Cannot open a special file... + RC = STATUS_ACCESS_DENIED; + try_return( RC ); + + } + if( DirectoryOnlyRequested && Type != EXT2_FT_DIR ) + { + RC = STATUS_NOT_A_DIRECTORY; + try_return( RC ); + } + if( FileOnlyRequested && Type == EXT2_FT_DIR ) + { + RC = STATUS_FILE_IS_A_DIRECTORY; + try_return(RC); + } + + PtrCurrFileObject = PtrNewFileObject; + // Things seem to be ok enough! + // Proceeing with the Open/Create... + + } + + + // + // Create an FCB and initialise it... + // + { + PtrExt2ObjectName PtrObjectName; + + // Initialising the object name... + PtrObjectName = Ext2AllocateObjectName(); + Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &CurrentName ); + // RtlInitUnicodeString( &PtrObjectName->ObjectName, CurrentName.Buffer ); + + if( !NT_SUCCESS( Ext2CreateNewFCB( + &PtrNextFCB, // the new FCB + ZeroSize, // AllocationSize, + ZeroSize, // EndOfFile, + PtrCurrFileObject, // The File Object + PtrVCB, + PtrObjectName ) ) ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if( Type == EXT2_FT_DIR ) + PtrNextFCB->FCBFlags |= EXT2_FCB_DIRECTORY; + else if( Type != EXT2_FT_REG_FILE ) + PtrNextFCB->FCBFlags |= EXT2_FCB_SPECIAL_FILE; + + PtrNextFCB->INodeNo = CurrInodeNo ; + PtrNextFCB->ParentINodeNo = PtrCurrFCB->INodeNo; + + if( PtrCurrFileObject == NULL && CurrInodeNo != EXT2_ROOT_INO ) + { + // This is an FCB created to cache the reads done while parsing + // Put this FCB on the ClosableFCBList + if( !PtrNextFCB->ClosableFCBs.OnClosableFCBList ) + { + InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, + &PtrNextFCB->ClosableFCBs.ClosableFCBList ); + PtrVCB->ClosableFCBs.Count++; + PtrNextFCB->ClosableFCBs.OnClosableFCBList = TRUE; + } + } + } + } + + // + // Still not done parsing... + // miles to go before I open... ;) + // + PtrCurrFCB = PtrNextFCB; + } + + PtrNewFCB = PtrNextFCB; + } + + + // If I get this far... + // it means, I have located the file... + // I even have an FCB to represent it!!! + + if ( NT_SUCCESS (RC) ) + { + + if ((PtrNewFCB->FCBFlags & EXT2_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) || + (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF ))) + { + RC = STATUS_FILE_IS_A_DIRECTORY; + try_return(RC); + } + + + // Check share access and fail if the share conflicts with an existing + // open. + + if (PtrNewFCB->OpenHandleCount > 0) + { + // The FCB is currently in use by some thread. + // We must check whether the requested access/share access + // conflicts with the existing open operations. + + if (!NT_SUCCESS(RC = IoCheckShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, + &(PtrNewFCB->FCBShareAccess), TRUE))) + { + // Ext2CloseCCB(PtrNewCCB); + try_return(RC); + } + } + else + { + IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess)); + } + + // + // Allocating a new CCB Structure... + // + Ext2CreateNewCCB( &PtrNewCCB, PtrNewFCB, PtrNewFileObject); + PtrNewFileObject->FsContext2 = (void *) PtrNewCCB; + Ext2CopyUnicodeString( &(PtrNewCCB->AbsolutePathName), &AbsolutePathName ); + + if( ReturnedInformation == -1 ) + { + // + // ReturnedInformation has not been set so far... + // + ReturnedInformation = FILE_OPENED; + } + + // If a supersede or overwrite was requested, do so now ... + if (RequestedDisposition == FILE_SUPERSEDE) + { + // Attempt the operation here ... + if( Ext2SupersedeFile( PtrNewFCB, PtrIrpContext) ) + { + ReturnedInformation = FILE_SUPERSEDED; + } + } + + else if ((RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF)) + { + // Attempt the overwrite operation... + if( Ext2OverwriteFile( PtrNewFCB, PtrIrpContext) ) + { + ReturnedInformation = FILE_OVERWRITTEN; + } + } + if( AllocationSize ) + { + if( ReturnedInformation == FILE_CREATED || + ReturnedInformation == FILE_SUPERSEDED ) + { + ULONG CurrentSize; + ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + for( CurrentSize = 0; CurrentSize < AllocationSize; CurrentSize += LogicalBlockSize ) + { + Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrNewFCB, PtrNewFileObject, FALSE ); + } + } + } + + if( ReturnedInformation == FILE_CREATED ) + { + // Allocate some data blocks if + // 1. initial file size has been specified... + // 2. if the file is a Directory... + // In case of (2) make entries for '.' and '..' + // Zero out the Blocks... + + UNICODE_STRING Name; + + if( DirectoryOnlyRequested ) + { + + Ext2CopyCharToUnicodeString( &Name, ".", 1 ); + Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->INodeNo); + + Name.Buffer[1] = '.'; + Name.Buffer[2] = '\0'; + Name.Length += 2; + Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->ParentINodeNo ); + Ext2DeallocateUnicodeString( &Name ); + } + } + if( OpenTargetDirectory ) + { + // + // Save the taget file name in the CCB... + // + Ext2CopyUnicodeString( + &PtrNewCCB->RenameLinkTargetFileName, + &RenameLinkTargetFileName ); + Ext2DeallocateUnicodeString( &RenameLinkTargetFileName ); + } + } + + try_exit: NOTHING; + + } + finally + { + if (AcquiredVCB) + { + ASSERT(PtrVCB); + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + + AcquiredVCB = FALSE; + DebugTrace(DEBUG_TRACE_MISC, "*** VCB released [Create]", 0); + + if( PtrNewFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Create]", PtrNewFileObject); + } + } + + if (AbsolutePathName.Buffer != NULL) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Create]", AbsolutePathName.Buffer ); + ExFreePool(AbsolutePathName.Buffer); + } + + // Complete the request unless we are here as part of unwinding + // when an exception condition was encountered, OR + // if the request has been deferred (i.e. posted for later handling) + if (RC != STATUS_PENDING) + { + // If we acquired any FCB resources, release them now ... + + // If any intermediate (directory) open operations were performed, + // implement the corresponding close (do *not* however close + // the target you have opened on behalf of the caller ...). + + if (NT_SUCCESS(RC)) + { + // Update the file object such that: + // (a) the FsContext field points to the NTRequiredFCB field + // in the FCB + // (b) the FsContext2 field points to the CCB created as a + // result of the open operation + + // If write-through was requested, then mark the file object + // appropriately + if (WriteThroughRequested) + { + PtrNewFileObject->Flags |= FO_WRITE_THROUGH; + } + DebugTrace( DEBUG_TRACE_SPECIAL, " === Create/Open successful", 0 ); + } + else + { + DebugTrace( DEBUG_TRACE_SPECIAL, " === Create/Open failed", 0 ); + // Perform failure related post-processing now + } + + // As long as this unwinding is not being performed as a result of + // an exception condition, complete the IRP ... + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) + { + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = ReturnedInformation; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + } + } + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2OpenVolume() +* +* Description: +* Open a logical volume for the caller. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2OpenVolume( +PtrExt2VCB PtrVCB, // volume to be opened +PtrExt2IrpContext PtrIrpContext, // IRP context +PIRP PtrIrp, // original/user IRP +unsigned short ShareAccess, // share access +PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) +PFILE_OBJECT PtrNewFileObject) // I/O Mgr. created file object +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2CCB PtrCCB = NULL; + + try { + // check for exclusive open requests (using share modes supplied) + // and determine whether it is even possible to open the volume + // with the specified share modes (e.g. if caller does not + // wish to share read or share write ...) + + // Use IoCheckShareAccess() and IoSetShareAccess() here ... + // They are defined in the DDK. + + // You might also wish to check the caller's security context + // to see whether you wish to allow the volume open or not. + // Use the SeAccessCheck() routine described in the DDK for this purpose. + + // create a new CCB structure + if (!(PtrCCB = Ext2AllocateCCB())) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + // initialize the CCB + PtrCCB->PtrFCB = (PtrExt2FCB)(PtrVCB); + InsertTailList(&(PtrVCB->VolumeOpenListHead), &(PtrCCB->NextCCB)); + + // initialize the CCB to point to the file object + PtrCCB->PtrFileObject = PtrNewFileObject; + + Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_VOLUME_OPEN); + + // initialize the file object appropriately + PtrNewFileObject->FsContext = (void *)( &(PtrVCB->CommonVCBHeader) ); + PtrNewFileObject->FsContext2 = (void *)(PtrCCB); + + // increment the number of outstanding open operations on this + // logical volume (i.e. volume cannot be dismounted) + + // You might be concerned about 32 bit wrap-around though I would + // argue that it is unlikely ... :-) + (PtrVCB->VCBOpenCount)++; + + // now set the IoStatus Information value correctly in the IRP + // (caller will set the status field) + PtrIrp->IoStatus.Information = FILE_OPENED; + + try_exit: NOTHING; + } + finally + { + NOTHING; + } + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2InitializeFCB() +* +* Description: +* Initialize a new FCB structure and also the sent-in file object +* (if supplied) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +************************************************************************* +void Ext2InitializeFCB( +PtrExt2FCB PtrNewFCB, // FCB structure to be initialized +PtrExt2VCB PtrVCB, // logical volume (VCB) pointer +PtrExt2ObjectName PtrObjectName, // name of the object +uint32 Flags, // is this a file/directory, etc. +PFILE_OBJECT PtrFileObject) // optional file object to be initialized +{ + // Initialize the disk dependent portion as you see fit + + // Initialize the two ERESOURCE objects + ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.MainResource)); + ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.PagingIoResource)); + + PtrNewFCB->FCBFlags |= EXT2_INITIALIZED_MAIN_RESOURCE | EXT2_INITIALIZED_PAGING_IO_RESOURCE | Flags; + + PtrNewFCB->PtrVCB = PtrVCB; + + // caller MUST ensure that VCB has been acquired exclusively + InsertTailList(&(PtrVCB->FCBListHead), &(PtrNewFCB->NextFCB)); + + // initialize the various list heads + InitializeListHead(&(PtrNewFCB->CCBListHead)); + +// PtrNewFCB->ReferenceCount = 1; +// PtrNewFCB->OpenHandleCount = 1; + + if( PtrObjectName ) + { + PtrNewFCB->FCBName = PtrObjectName; + } + + if ( PtrFileObject ) + { + PtrFileObject->FsContext = (void *)(&(PtrNewFCB->NTRequiredFCB)); + } + + return; +} +*/ + +/************************************************************************* +* +* Function: Ext2OpenRootDirectory() +* +* Description: +* Open the root directory for a volume +* +* +* Expected Interrupt Level (for execution) : +* +* ??? +* +* Return Value: None +* +*************************************************************************/ +NTSTATUS Ext2OpenRootDirectory( + PtrExt2VCB PtrVCB, // volume + PtrExt2IrpContext PtrIrpContext, // IRP context + PIRP PtrIrp, // original/user IRP + unsigned short ShareAccess, // share access + PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) + PFILE_OBJECT PtrNewFileObject // I/O Mgr. created file object + ) +{ + // Declerations... + PtrExt2CCB PtrCCB; + + ASSERT( PtrVCB ); + ASSERT( PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + ASSERT( PtrVCB->PtrRootDirectoryFCB ); + AssertFCB( PtrVCB->PtrRootDirectoryFCB ); + + PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO; + + // Create a new CCB... + Ext2CreateNewCCB( &PtrCCB, PtrVCB->PtrRootDirectoryFCB, PtrNewFileObject); + PtrNewFileObject->FsContext = (void *) &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader); + PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY; + PtrNewFileObject->FsContext2 = (void *) PtrCCB; + PtrNewFileObject->SectionObjectPointer = &PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject; + PtrNewFileObject->Vpb = PtrVCB->PtrVPB; + + Ext2CopyUnicodeString( &(PtrCCB->AbsolutePathName), &PtrVCB->PtrRootDirectoryFCB->FCBName->ObjectName ); + + + return STATUS_SUCCESS; +} + + + +PtrExt2FCB Ext2LocateChildFCBInCore( + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrName, + ULONG ParentInodeNo ) +{ + + PtrExt2FCB PtrFCB = NULL; + ULONG InodeNo = 0; + PLIST_ENTRY PtrEntry; + + if( IsListEmpty( &(PtrVCB->FCBListHead) ) ) + { + return NULL; // Failure; + } + + for( PtrEntry = PtrVCB->FCBListHead.Flink; + PtrEntry != &PtrVCB->FCBListHead; + PtrEntry = PtrEntry->Flink ) + { + PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB ); + ASSERT( PtrFCB ); + if( PtrFCB->ParentINodeNo == ParentInodeNo ) + { + if( RtlCompareUnicodeString( &PtrFCB->FCBName->ObjectName, PtrName, TRUE ) == 0 ) + return PtrFCB; + } + } + + return NULL; +} + +PtrExt2FCB Ext2LocateFCBInCore( + PtrExt2VCB PtrVCB, + ULONG InodeNo ) +{ + PtrExt2FCB PtrFCB = NULL; + PLIST_ENTRY PtrEntry; + + if( IsListEmpty( &(PtrVCB->FCBListHead) ) ) + { + return NULL; // Failure; + } + + for( PtrEntry = PtrVCB->FCBListHead.Flink; + PtrEntry != &PtrVCB->FCBListHead; + PtrEntry = PtrEntry->Flink ) + { + PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB ); + ASSERT( PtrFCB ); + if( PtrFCB->INodeNo == InodeNo ) + { + return PtrFCB; + } + } + + return NULL; +} + + +ULONG Ext2LocateFileInDisk ( + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrCurrentName, + PtrExt2FCB PtrParentFCB, + ULONG *Type ) +{ + + PtrExt2FCB PtrNewFCB = NULL; + PFILE_OBJECT PtrFileObject = NULL; + ULONG InodeNo = 0; + + *Type = EXT2_FT_UNKNOWN; + + // 1. + // Initialize the Blocks in the FCB... + // + Ext2InitializeFCBInodeInfo( PtrParentFCB ); + + + // 2. + // Is there a file object I can use for caching?? + // If not create one... + // + if( !PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject ) + { + // + // No Directory File Object? + // No problem, will create one... + // + + // Acquire the MainResource first though... + + PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject = IoCreateStreamFileObject(NULL, PtrVCB->TargetDeviceObject ); + PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; + + if( !PtrFileObject ) + { + Ext2BreakPoint(); + return 0; + } + PtrFileObject->ReadAccess = TRUE; + PtrFileObject->WriteAccess = TRUE; + + // Associate the file stream with the Volume parameter block... + PtrFileObject->Vpb = PtrVCB->PtrVPB; + + // No caching as yet... + PtrFileObject->PrivateCacheMap = NULL; + + // this establishes the FCB - File Object connection... + PtrFileObject->FsContext = (void *)( & (PtrParentFCB->NTRequiredFCB.CommonFCBHeader) ); + + // Initialize the section object pointer... + PtrFileObject->SectionObjectPointer = &(PtrParentFCB->NTRequiredFCB.SectionObject); + } + else + { + // + // I do have a file object... + // I am using it now! + // + PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; + } + + // 3. + // Got hold of a file object? Good ;) + // Now initiating Caching, pinned access to be precise ... + // + if (PtrFileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrParentFCB ); // The context used in callbacks + } + + // 4. + // Getting down to the real business now... ;) + // Read in the directory contents and do a search + // a sequential search to be precise... + // Wish Mm'm Renuga were reading this + // Would feel proud... ;) + // + { + LARGE_INTEGER StartBufferOffset; + ULONG PinBufferLength; + ULONG BufferIndex; + PBCB PtrBCB = NULL; + BYTE * PtrPinnedBlockBuffer = NULL; + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + BOOLEAN Found; + int i; + + + StartBufferOffset.QuadPart = 0; + + // + // Read in the whole damn directory + // **Bad programming** + // Will do for now. + // + PinBufferLength = PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; + if (!CcMapData( PtrFileObject, + &StartBufferOffset, + PinBufferLength, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedBlockBuffer ) ) + { + + + } + // + // Walking through now... + // + + for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) + { + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; + if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 || PtrDirEntry->inode == 0) + { + // Invalid entry... + // Ignore... + continue; + } + // + // Comparing ( case sensitive ) + // Directory entry is not NULL terminated... + // nor is the CurrentName... + // + if( PtrDirEntry->name_len != (PtrCurrentName->Length / 2) ) + continue; + + for( i = 0, Found = TRUE ; i < PtrDirEntry->name_len ; i++ ) + { + if( PtrDirEntry->name[ i ] != PtrCurrentName->Buffer[ i ] ) + { + Found = FALSE; + break; + + } + } + + } + if( Found ) + { + InodeNo = PtrDirEntry->inode; + + if( PtrDirEntry->file_type == EXT2_FT_UNKNOWN ) + { + + // Old Fashioned Directory entries... + // Will have to read in the Inode to determine the File Type... + EXT2_INODE Inode; + // PtrInode = Ext2AllocatePool( NonPagedPool, sizeof( EXT2_INODE ) ); + Ext2ReadInode( PtrVCB, InodeNo, &Inode ); + + if( Ext2IsModeRegularFile( Inode.i_mode ) ) + { + *Type = EXT2_FT_REG_FILE; + } + else if ( Ext2IsModeDirectory( Inode.i_mode) ) + { + // Directory... + *Type = EXT2_FT_DIR; + } + else if( Ext2IsModeSymbolicLink(Inode.i_mode) ) + { + *Type = EXT2_FT_SYMLINK; + } + else if( Ext2IsModePipe(Inode.i_mode) ) + { + *Type = EXT2_FT_FIFO; + } + else if( Ext2IsModeCharacterDevice(Inode.i_mode) ) + { + *Type = EXT2_FT_CHRDEV; + } + else if( Ext2IsModeBlockDevice(Inode.i_mode) ) + { + *Type = EXT2_FT_BLKDEV; + } + else if( Ext2IsModeSocket(Inode.i_mode) ) + { + *Type = EXT2_FT_SOCK; + } + else + { + *Type = EXT2_FT_UNKNOWN; + } + + //DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Create]", PtrInode ); + //ExFreePool( PtrInode ); + } + else + { + *Type = PtrDirEntry->file_type; + } + } + + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + + return InodeNo; + } +} + + +/************************************************************************* +* +* Function: Ext2CreateFile() +* +* Description: +* Creates a new file on the disk +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Restrictions: +* Expects the VCB to be acquired Exclusively before being invoked +* +* Return Value: None +* +*************************************************************************/ +ULONG Ext2CreateFile( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + PUNICODE_STRING PtrName, + PtrExt2FCB PtrParentFCB, + ULONG Type) +{ + EXT2_INODE Inode, ParentInode; + + ULONG NewInodeNo = 0; + BOOLEAN FCBAcquired = FALSE; + + ULONG LogicalBlockSize = 0; + + try + { + + + // 0. Verify if the creation is possible,,, + if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE ) + { + // + // Can create only a directory or a regular file... + // + return 0; + } + + // 1. Allocate an i-node... + + NewInodeNo = Ext2AllocInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo ); + + // NewInodeNo = 12; + + if( !NewInodeNo ) + { + return 0; + } + + // 2. Acquire the Parent FCB Exclusively... + if( !ExAcquireResourceExclusiveLite(&( PtrParentFCB->NTRequiredFCB.MainResource ), TRUE) ) + { + Ext2DeallocInode( PtrIrpContext, PtrVCB, NewInodeNo ); + try_return( NewInodeNo = 0); + } + FCBAcquired = TRUE; + + // 3. Make an entry in the parent Directory... + ASSERT( PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject ); + + Ext2MakeNewDirectoryEntry( + PtrIrpContext, + PtrParentFCB, + PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject, + PtrName, Type, NewInodeNo ); + + + // 4. Initialize an inode entry and write it to disk... + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + { + // To be deleted + Ext2ReadInode( PtrVCB, NewInodeNo, &Inode ); + } + + RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) ); + if( Type == EXT2_FT_DIR ) + { + Inode.i_mode = 0x41ff; + + // In addition to the usual link, + // there will be an additional link in the directory itself - the '.' entry + Inode.i_links_count = 2; + + // Incrementing the link count for the parent as well... + Ext2ReadInode( PtrVCB, PtrParentFCB->INodeNo, &ParentInode ); + ParentInode.i_links_count++; + Ext2WriteInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo, &ParentInode ); + + } + else + { + Inode.i_mode = 0x81ff; + Inode.i_links_count = 1; + } + + + { + // + // Setting the time fields in the inode... + // + ULONG Time; + Time = Ext2GetCurrentTime(); + Inode.i_ctime = Time; + Inode.i_atime = Time; + Inode.i_mtime = Time; + Inode.i_dtime = 0; // Deleted time; + } + + Ext2WriteInode( PtrIrpContext, PtrVCB, NewInodeNo, &Inode ); + + try_exit: NOTHING; + } + finally + { + if( FCBAcquired ) + { + Ext2ReleaseResource( &(PtrParentFCB->NTRequiredFCB.MainResource) ); + } + } + + return NewInodeNo ; +} + +/************************************************************************* +* +* Function: Ext2CreateFile() +* +* Description: +* Overwrites an existing file on the disk +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Restrictions: +* Expects the VCB to be acquired Exclusively before being invoked +* +* Return Value: None +* +*************************************************************************/ +BOOLEAN Ext2OverwriteFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext) +{ + EXT2_INODE Inode; + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + ULONG i; + ULONG Time; + Time = Ext2GetCurrentTime(); + + Ext2InitializeFCBInodeInfo( PtrFCB ); + // 1. + // Update the inode... + if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + Inode.i_size = 0; + Inode.i_blocks = 0; + Inode.i_atime = Time; + Inode.i_mtime = Time; + Inode.i_dtime = 0; + + for( i = 0; i < EXT2_N_BLOCKS; i++ ) + { + Inode.i_block[ i ] = 0; + } + + if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + // 2. + // Release all the data blocks... + if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) ) + { + return FALSE; + } + + Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); + Ext2InitializeFCBInodeInfo( PtrFCB ); + + return TRUE; +} + +/************************************************************************* +* +* Function: Ext2SupersedeFile() +* +* Description: +* Supersedes an existing file on the disk +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Restrictions: +* Expects the VCB to be acquired Exclusively before being invoked +* +* Return Value: None +* +*************************************************************************/ +BOOLEAN Ext2SupersedeFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext) +{ + EXT2_INODE Inode; + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + ULONG i; + + Ext2InitializeFCBInodeInfo( PtrFCB ); + + // 1. + // Initialize the inode... + RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) ); + + // Setting the file mode... + // This operation is allowed only for a regular file... + Inode.i_mode = 0x81ff; + + // Maintaining the old link count... + Inode.i_links_count = PtrFCB->LinkCount; + + // Setting the time fields in the inode... + { + ULONG Time; + Time = Ext2GetCurrentTime(); + Inode.i_ctime = Time; + Inode.i_atime = Time; + Inode.i_mtime = Time; + Inode.i_dtime = 0; // Deleted time; + } + + if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + // 2. + // Release all the data blocks... + if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) ) + { + return FALSE; + } + + Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); + Ext2InitializeFCBInodeInfo( PtrFCB ); + + return TRUE; +} diff --git a/reactos/drivers/filesystems/ext2/src/devcntrl.c b/reactos/drivers/filesystems/ext2/src/devcntrl.c new file mode 100644 index 00000000000..02389865f6c --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/devcntrl.c @@ -0,0 +1,210 @@ +/************************************************************************* +* +* File: devcntrl.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Device IOCTL" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_DEVICE_CONTROL +#define DEBUG_LEVEL DEBUG_TRACE_DEVCTRL + + +#if(_WIN32_WINNT < 0x0400) +#define IOCTL_REDIR_QUERY_PATH CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 99, METHOD_NEITHER, FILE_ANY_ACCESS) + +typedef struct _QUERY_PATH_REQUEST +{ + ULONG PathNameLength; + PIO_SECURITY_CONTEXT SecurityContext; + WCHAR FilePathName[1]; +} QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST; + +typedef struct _QUERY_PATH_RESPONSE +{ + ULONG LengthAccepted; +} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE; +#endif + + +/************************************************************************* +* +* Function: Ext2DeviceControl() +* +* Description: +* The I/O Manager will invoke this routine to handle a Device IOCTL +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2DeviceControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + // Ext2BreakPoint(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Device Control IRP Received...", 0); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonDeviceControl(PtrIrpContext, Irp); + + } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonDeviceControl() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonDeviceControl( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PIO_STACK_LOCATION PtrNextIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + ULONG IoControlCode = 0; + void *BufferPointer = NULL; + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + + + if( PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) + { + PtrVCB = (PtrExt2VCB)(PtrFCB); + } + else + { + AssertFCB( PtrFCB ); + ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB); + PtrVCB = PtrFCB->PtrVCB; + } + + // Get the IoControlCode value + IoControlCode = PtrIoStackLocation->Parameters.DeviceIoControl.IoControlCode; + + // You may wish to allow only volume open operations. + + // Invoke the lower level driver in the chain. + PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp); + *PtrNextIoStackLocation = *PtrIoStackLocation; + // Set a completion routine. + IoSetCompletionRoutine(PtrIrp, Ext2DevIoctlCompletion, NULL, TRUE, TRUE, TRUE); + // Send the request. + RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); + + try_exit: NOTHING; + + } + finally + { + // Release the IRP context + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) + { + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + } + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2DevIoctlCompletion() +* +* Description: +* Completion routine. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS +* +*************************************************************************/ +NTSTATUS Ext2DevIoctlCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP PtrIrp, +void *Context) +{ + if (PtrIrp->PendingReturned) { + IoMarkIrpPending(PtrIrp); + } + + return(STATUS_SUCCESS); +} diff --git a/reactos/drivers/filesystems/ext2/src/dircntrl.c b/reactos/drivers/filesystems/ext2/src/dircntrl.c new file mode 100644 index 00000000000..759f2c25212 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/dircntrl.c @@ -0,0 +1,937 @@ +/************************************************************************* +* +* File: dircntrl.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "directory control" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_DIR_CONTROL + +#define DEBUG_LEVEL (DEBUG_TRACE_DIRCTRL) + + +/************************************************************************* +* +* Function: Ext2DirControl() +* +* Description: +* The I/O Manager will invoke this routine to handle a directory control +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2DirControl( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "DIR Control IRP received...", 0); + + + FsRtlEnterFileSystem(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonDirControl(PtrIrpContext, Irp); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2CommonDirControl() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonDirControl( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Get the FCB and CCB pointers + PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + + AssertFCB( PtrFCB ); + + + // Get some of the parameters supplied to us + switch (PtrIoStackLocation->MinorFunction) { + case IRP_MN_QUERY_DIRECTORY: +#ifdef _GNU_NTIFS_ + RC = Ext2QueryDirectory(PtrIrpContext, PtrIrp, (PEXTENDED_IO_STACK_LOCATION)PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB); +#else + RC = Ext2QueryDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB); +#endif + break; + case IRP_MN_NOTIFY_CHANGE_DIRECTORY: + { + RC = STATUS_NOT_IMPLEMENTED; + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = 0; + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + // RC = Ext2NotifyChangeDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB); + break; + default: + // This should not happen. + RC = STATUS_INVALID_DEVICE_REQUEST; + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = 0; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_NO_INCREMENT); + break; + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2QueryDirectory() +* +* Description: +* Query directory request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2QueryDirectory( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +#ifdef _GNU_NTIFS_ +PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, +#else +PIO_STACK_LOCATION PtrIoStackLocation, +#endif +PFILE_OBJECT PtrFileObject, +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN CompleteRequest = TRUE; + BOOLEAN PostRequest = FALSE; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + BOOLEAN CanWait = FALSE; + PtrExt2VCB PtrVCB = NULL; + BOOLEAN AcquiredFCB = FALSE; + unsigned long BufferLength = 0; + unsigned long BufferIndex = 0; + unsigned long FileIndex = 0; + PUNICODE_STRING PtrSearchPattern = NULL; + FILE_INFORMATION_CLASS FileInformationClass; + BOOLEAN RestartScan = FALSE; + BOOLEAN ReturnSingleEntry = FALSE; + BOOLEAN IndexSpecified = FALSE; + unsigned char *Buffer = NULL; + BOOLEAN FirstTimeQuery = FALSE; + unsigned long StartingIndexForSearch = 0; + unsigned long BytesReturned = 0; + BOOLEAN BufferUsedup = FALSE; + + BOOLEAN SearchWithWildCards = FALSE; + + PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL; + PFILE_FULL_DIR_INFORMATION FullDirInformation = NULL; + PFILE_DIRECTORY_INFORMATION DirectoryInformation = NULL; + PFILE_NAMES_INFORMATION NamesInformation = NULL; + + + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + PEXT2_INODE PtrInode = NULL; + + unsigned long LogicalBlockSize; + + unsigned long ThisBlock; + + // The starting Physical Block No... + //LARGE_INTEGER StartPhysicalBlock; + LARGE_INTEGER StartBufferOffset ; + ULONG PinBufferLength; + + // Buffer Control Block + PBCB PtrBCB = NULL; + BYTE * PtrPinnedBlockBuffer = NULL; + + unsigned int i,j; + + DebugTrace(DEBUG_TRACE_MISC, " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer ); + + try + { + // Validate the sent-in FCB + if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) + { + // We will only allow notify requests on directories. + RC = STATUS_INVALID_PARAMETER; + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + PtrVCB = PtrFCB->PtrVCB; + + // + // Asynchronous IO requested + // Posting request... + // + /* + * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL + * requests aren't handled in the worker thread yet. I tried + * adding handling of them to the worked routine, but there + * were problems with accessing the PtrIoStackLocation-> + * Parameters.QueryDirectory.FileName variable. + * -- Filip Navara, 18/08/2004 + */ +#if 0 + if (!CanWait) + { + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } +#endif + + // Obtain the callers parameters + BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length; + PtrSearchPattern = ( PUNICODE_STRING ) PtrIoStackLocation->Parameters.QueryDirectory.FileName; + FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass; + FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex; + + // Some additional arguments that affect the FSD behavior + RestartScan = (PtrIoStackLocation->Flags & SL_RESTART_SCAN); + ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY); + IndexSpecified = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED); + + // + // Acquiring exclusive access to the FCB. + // This is not mandatory + // + DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); + + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); + AcquiredFCB = TRUE; + + // We must determine the buffer pointer to be used. Since this + // routine could either be invoked directly in the context of the + // calling thread, or in the context of a worker thread, here is + // a general way of determining what we should use. + Buffer = Ext2GetCallersBuffer ( PtrIrp ); + + // The method of determining where to look from and what to look for is + // unfortunately extremely confusing. However, here is a methodology you + // you can broadly adopt: + // (a) You have to maintain a search buffer per CCB structure. + // (b) This search buffer is initialized the very first time + // a query directory operation is performed using the file object. + // (For the sample FSD, the search buffer is stored in the + // DirectorySearchPattern field) + // However, the caller still has the option of "overriding" this stored + // search pattern by supplying a new one in a query directory operation. + // + + if( PtrCCB->DirectorySearchPattern.Length ) + { + if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0); + } + DebugTrace(DEBUG_TRACE_MISC, " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); + } + + if (PtrSearchPattern != NULL) + { + // User has supplied a search pattern + // Now validate that the search pattern is legitimate + + if ( PtrCCB->DirectorySearchPattern.Length == 0 ) + { + // This must be the very first query request. + FirstTimeQuery = TRUE; + } + else + { + // We should ignore the search pattern in the CCB and instead, + // use the user-supplied pattern for this particular query + // directory request. + Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); + } + + // Now, allocate enough memory to contain the caller + // supplied search pattern and fill in the DirectorySearchPattern + // field in the CCB + Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern ); + /* + PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) ); + ASSERT(PtrCCB->DirectorySearchPattern); + RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) ); + */ + } + else if ( PtrCCB->DirectorySearchPattern.Length == 0 ) + { + // This MUST be the first directory query operation (else the + // DirectorySearchPattern field would never be empty. Also, the caller + // has neglected to provide a pattern so we MUST invent one. + // Use "*" (following NT conventions) as your search pattern + // and store it in the PtrCCB->DirectorySearchPattern field. + + /* + PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") ); + ASSERT(PtrCCB->DirectorySearchPattern); + RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/ + + Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" ); + + FirstTimeQuery = TRUE; + } + else + { + // The caller has not supplied any search pattern... + // Using previously supplied pattern + PtrSearchPattern = &PtrCCB->DirectorySearchPattern; + } + + if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 ); + } + DebugTrace(DEBUG_TRACE_MISC, " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); + SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern ); + + // There is one other piece of information that your FSD must store + // in the CCB structure for query directory support. This is the index + // value (i.e. the offset in your on-disk directory structure) from + // which you should start searching. + // However, the flags supplied with the IRP can make us override this + // as well. + + if (FileIndex) + { + // Caller has told us wherefrom to begin. + // You may need to round this to an appropriate directory entry + // entry alignment value. + StartingIndexForSearch = FileIndex; + } + else if (RestartScan) + { + StartingIndexForSearch = 0; + } + else + { + // Get the starting offset from the CCB. + StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart; + } + + // Read in the file inode if it hasn't already been read... + Ext2InitializeFCBInodeInfo( PtrFCB ); + + if (PtrFileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), + TRUE, // We will utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrCCB); // The context used in callbacks + } + + + // + // Read in the next Data Block of this directory + // + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize ); + StartBufferOffset.QuadPart *= LogicalBlockSize; // This should be the StartBufferOffset alaigned to LBlock boundary... + + PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart; + + if ( !CcMapData( PtrFileObject, + &StartBufferOffset, + PinBufferLength, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedBlockBuffer ) ) + { + // Read Failure + DebugTrace(DEBUG_TRACE_MISC, "Cache read failiure while reading in volume meta data", 0); + try_return( STATUS_ACCESS_DENIED ); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); + } + + PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE ) ); + + // + // Walking through the directory entries... + for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; ) + { + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ]; + + StartingIndexForSearch += PtrDirEntry->rec_len; + PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch; + + if( PtrDirEntry->inode == 0 ) + { + continue; + } + if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 ) + { + // + // This should not happen + // Hqw can this be so!!! + // + Ext2BreakPoint(); + if( BothDirInformation ) + { + BothDirInformation->NextEntryOffset = 0; + } + if( !BytesReturned ) + { + if( FirstTimeQuery ) + RC = STATUS_NO_SUCH_FILE; + else + RC = STATUS_NO_MORE_FILES; + } + break; + } + + // Does this entry match the search criterian? + // Checking + // + { + UNICODE_STRING FileName; + LONG Matched = 0; + // Constructing a counted Unicode string out of PtrDirEntry + Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len ); + + if ( SearchWithWildCards ) + { + Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL ); + } + else + { + Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE ); + } + + Ext2DeallocateUnicodeString( &FileName ); + if( !Matched ) + { + continue; + } + } + + switch( FileInformationClass ) + { + case FileBothDirectoryInformation: + + DebugTrace(DEBUG_TRACE_DIRINFO, " === FileBothDirectoryInformation", 0 ); + ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION ); + ThisBlock += PtrDirEntry->name_len*2; + ThisBlock = Ext2QuadAlign( ThisBlock ); + + if( ( BufferIndex + ThisBlock ) > BufferLength ) + { + // + // Next entry won't fit into the buffer... + // will have to return... + // :( + // + if( BothDirInformation ) + BothDirInformation->NextEntryOffset = 0; + if( !BytesReturned ) + RC = STATUS_NO_MORE_FILES; + BufferUsedup = TRUE; + break; + } + + Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); + if( !PtrInode ) + { + try_return( RC = STATUS_UNSUCCESSFUL ); + } + + BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) ); + BothDirInformation->EaSize = 0; + BothDirInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; + BothDirInformation->EndOfFile.QuadPart = PtrInode->i_size; + BothDirInformation->ChangeTime.QuadPart = 0; + + BothDirInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; + BothDirInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; + + BothDirInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); + BothDirInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); + + // Getting the file type... + BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; + if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) + { + // Not a reqular file... + if( Ext2IsModeDirectory( PtrInode->i_mode) ) + { + // Directory... + BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else + { + // Special File... + // Treated with respect... ;) + // + BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); + // FILE_ATTRIBUTE_DEVICE + } + if ( Ext2IsModeHidden( PtrInode->i_mode ) ) + { + BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) + { + BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + } + + BothDirInformation->FileIndex = StartingIndexForSearch; + BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; + BothDirInformation->ShortNameLength = 0; + BothDirInformation->ShortName[0] = 0; + + // Copying out the name as WCHAR null terminated strings + for( j = 0; j< PtrDirEntry->name_len ; j ++ ) + { + // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j]; + BothDirInformation->FileName[ j ] = PtrDirEntry->name[j]; + // if( j < 11 ) + // BothDirInformation->ShortName[j] = PtrDirEntry->name[j];; + } + + /* + if( j < 11 ) + { + BothDirInformation->ShortNameLength = j * 2 + 2; + BothDirInformation->ShortName[ j ] = 0; + } + else + { + BothDirInformation->ShortNameLength = 24; + BothDirInformation->ShortName[ 11 ] = 0; + }*/ + + BothDirInformation->FileName[ j ] = 0; + BytesReturned += ThisBlock; + BufferIndex += ThisBlock; + + if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) + BothDirInformation->NextEntryOffset = ThisBlock; + else + BothDirInformation->NextEntryOffset = 0; + break; + + case FileDirectoryInformation: + // DirectoryInformation + DebugTrace(DEBUG_TRACE_DIRINFO, " === FileDirectoryInformation", 0 ); + ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION ); + ThisBlock += PtrDirEntry->name_len*2; + ThisBlock = Ext2QuadAlign( ThisBlock ); + + if( ( BufferIndex + ThisBlock ) > BufferLength ) + { + // + // Next entry won't fit into the buffer... + // will have to return... + // :( + // + if( DirectoryInformation ) + DirectoryInformation->NextEntryOffset = 0; + if( !BytesReturned ) + RC = STATUS_NO_MORE_FILES; + BufferUsedup = TRUE; + break; + } + + Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); + if( !PtrInode ) + { + try_return( RC = STATUS_UNSUCCESSFUL ); + } + + DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) ); + DirectoryInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; + DirectoryInformation->EndOfFile.QuadPart = PtrInode->i_size; + DirectoryInformation->ChangeTime.QuadPart = 0; + + DirectoryInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; + DirectoryInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; + + DirectoryInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); + DirectoryInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); + + // Getting the file type... + DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; + if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) + { + // Not a reqular file... + if( Ext2IsModeDirectory( PtrInode->i_mode) ) + { + // Directory... + DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else + { + // Special File... + // Treated with respect... ;) + // + DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); + // FILE_ATTRIBUTE_DEVICE + } + if ( Ext2IsModeHidden( PtrInode->i_mode ) ) + { + DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) + { + DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + } + + DirectoryInformation->FileIndex = StartingIndexForSearch; + DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; + + // Copying out the name as WCHAR null terminated strings + for( j = 0; j< PtrDirEntry->name_len ; j ++ ) + { + DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j]; + } + + DirectoryInformation->FileName[ j ] = 0; + BytesReturned += ThisBlock; + BufferIndex += ThisBlock; + + if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) + DirectoryInformation->NextEntryOffset = ThisBlock; + else + DirectoryInformation->NextEntryOffset = 0; + break; + + case FileFullDirectoryInformation: + // FullDirInformation-> + DebugTrace(DEBUG_TRACE_DIRINFO, " === FileFullDirectoryInformation - Not handled", 0 ); + try_return( RC ); + case FileNamesInformation: + // NamesInformation-> + DebugTrace(DEBUG_TRACE_DIRINFO, " === FileNamesInformation - Not handled", 0 ); + try_return( RC ); + default: + DebugTrace(DEBUG_TRACE_DIRINFO, " === Invalid Dir Info class - Not handled", 0 ); + try_return( RC = STATUS_INVALID_INFO_CLASS ); + } + if( ReturnSingleEntry ) + { + break; + } + }// end of for... + + + + if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) ) + { + Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); + PtrCCB->CurrentByteOffset.QuadPart = 0; + if( FirstTimeQuery ) + RC = STATUS_NO_SUCH_FILE; + else + RC = STATUS_NO_MORE_FILES; + try_return( RC ); + } + else if( BytesReturned ) + { + BothDirInformation->NextEntryOffset = 0; + } + + try_exit: NOTHING; + } + finally + { + + if( PtrInode ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [DirCtrl]", PtrInode ); + ExFreePool( PtrInode ); + } + + if( PtrBCB ) + { + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + if (PostRequest) + { + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in [DirCtrl]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + } + + // Map the users buffer and then post the request. + RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength); + ASSERT(NT_SUCCESS(RC)); + + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + + } + else if (!(PtrIrpContext->IrpContextFlags & + EXT2_IRP_CONTEXT_EXCEPTION)) + { + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [DirCtrl]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + } + + // Complete the request. + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = BytesReturned; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + + // Flush the saved BCBs... + // Ext2FlushSavedBCBs ( PtrIrpContext ); + + } + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2NotifyChangeDirectory() +* +* Description: +* Handle the notify request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2NotifyChangeDirectory( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +#ifdef _GNU_NTIFS_ +PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, +#else +PIO_STACK_LOCATION PtrIoStackLocation, +#endif +PFILE_OBJECT PtrFileObject, +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN CompleteRequest = FALSE; + BOOLEAN PostRequest = FALSE; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + BOOLEAN CanWait = FALSE; + ULONG CompletionFilter = 0; + BOOLEAN WatchTree = FALSE; + PtrExt2VCB PtrVCB = NULL; + BOOLEAN AcquiredFCB = FALSE; + + try { + + // Validate the sent-in FCB + if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) { + // We will only allow notify requests on directories. + RC = STATUS_INVALID_PARAMETER; + CompleteRequest = TRUE; + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + PtrVCB = PtrFCB->PtrVCB; + + // Acquire the FCB resource shared + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared[DirCtrl]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [DirCtrl]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + AcquiredFCB = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); + + // Obtain some parameters sent by the caller + CompletionFilter = PtrIoStackLocation->Parameters.NotifyDirectory.CompletionFilter; + WatchTree = (PtrIoStackLocation->Flags & SL_WATCH_TREE ? TRUE : FALSE); + + // If you wish to capture the subject context, you can do so as + // follows: + // { + // PSECURITY_SUBJECT_CONTEXT SubjectContext; + // SubjectContext = Ext2AllocatePool(PagedPool, + // sizeof(SECURITY_SUBJECT_CONTEXT) ); + // SeCaptureSubjectContext(SubjectContext); + // } + + FsRtlNotifyFullChangeDirectory((PNOTIFY_SYNC)&(PtrVCB->NotifyIRPMutex), &(PtrVCB->NextNotifyIRP), (void *)PtrCCB, + (PSTRING)(PtrFCB->FCBName->ObjectName.Buffer), WatchTree, FALSE, CompletionFilter, PtrIrp, + NULL, // Ext2TraverseAccessCheck(...) ? + NULL); // SubjectContext ? + + RC = STATUS_PENDING; + + try_exit: NOTHING; + + } + finally + { + + if (PostRequest) + { + // Perform appropriate post related processing here + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in DirCtrl", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + AcquiredFCB = FALSE; + } + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + else if (CompleteRequest) + { + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = 0; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } else { + // Simply free up the IrpContext since the IRP has been queued + Ext2ReleaseIrpContext(PtrIrpContext); + } + + // Release the FCB resources if acquired. + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FReleased in [DirCtrl]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + AcquiredFCB = FALSE; + } + + } + + return(RC); +} diff --git a/reactos/drivers/filesystems/ext2/src/ext2.rc b/reactos/drivers/filesystems/ext2/src/ext2.rc new file mode 100644 index 00000000000..cadc35f7d0c --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/ext2.rc @@ -0,0 +1,116 @@ +//Microsoft Developer Studio generated resource script. +// +#include "../inc/resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +/* REACTOS FIXME */ +/* #include "ntverp.h" */ + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "..\\inc\\resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""ntverp.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,3 + PRODUCTVERSION 0,0,0,3 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x29L +#else + FILEFLAGS 0x28L +#endif + FILEOS 0x40004L + FILETYPE 0x3L + FILESUBTYPE 0x7L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Ext2 File System Driver\0" + VALUE "CompanyName", "Purayidathil\0" + VALUE "FileDescription", "Ext2 File System Driver\0" + VALUE "FileVersion", "0, 0, 0, 3\0" + VALUE "InternalName", "ext2.sys\0" + VALUE "LegalCopyright", "Copyright © 2002 Manoj Paul Joseph\0" + VALUE "LegalTrademarks", " - \0" + VALUE "OriginalFilename", "ext2.sys\0" + VALUE "PrivateBuild", " - \0" + VALUE "ProductName", "Ext2 File System Driver for Windows NT\0" + VALUE "ProductVersion", "0, 0, 0, 3\0" + VALUE "SpecialBuild", " - \0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/reactos/drivers/filesystems/ext2/src/ext2init.c b/reactos/drivers/filesystems/ext2/src/ext2init.c new file mode 100644 index 00000000000..3df67efc60f --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/ext2init.c @@ -0,0 +1,381 @@ +/************************************************************************* +* +* File: ext2init.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* This file contains the initialization code for the kernel mode +* Ext2 FSD module. The DriverEntry() routine is called by the I/O +* sub-system to initialize the FSD. +* +* Author: Manoj Paul Joseph +* +*************************************************************************/ + + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_INIT +#define DEBUG_LEVEL (DEBUG_TRACE_INIT) + +#define EXT2_FS_NAME L"\\ext2" + +// global variables are declared here +Ext2Data Ext2GlobalData; + + +/************************************************************************* +* +* Function: DriverEntry() +* +* Description: +* This routine is the standard entry point for all kernel mode drivers. +* The routine is invoked at IRQL PASSIVE_LEVEL in the context of a +* system worker thread. +* All FSD specific data structures etc. are initialized here. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (will cause driver to be unloaded). +* +*************************************************************************/ +NTSTATUS DriverEntry( +PDRIVER_OBJECT DriverObject, // created by the I/O sub-system +PUNICODE_STRING RegistryPath) // path to the registry key +{ + NTSTATUS RC = STATUS_SUCCESS; + UNICODE_STRING DriverDeviceName; + BOOLEAN RegisteredShutdown = FALSE; + +#if 0 + Ext2BreakPoint(); +#endif + + try + { + try + { + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Ext2 File System Driver Entry <<<<<<<", 0); + // initialize the global data structure + RtlZeroMemory(&Ext2GlobalData, sizeof(Ext2GlobalData)); + + // initialize some required fields + Ext2GlobalData.NodeIdentifier.NodeType = EXT2_NODE_TYPE_GLOBAL_DATA; + Ext2GlobalData.NodeIdentifier.NodeSize = sizeof(Ext2GlobalData); + + // initialize the global data resource and remember the fact that + // the resource has been initialized + RC = ExInitializeResourceLite(&(Ext2GlobalData.GlobalDataResource)); + ASSERT(NT_SUCCESS(RC)); + Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_RESOURCE_INITIALIZED); + + // keep a ptr to the driver object sent to us by the I/O Mgr + Ext2GlobalData.Ext2DriverObject = DriverObject; + + // initialize the mounted logical volume list head + InitializeListHead( &( Ext2GlobalData.NextVCB ) ); + + // before we proceed with any more initialization, read in + // user supplied configurable values ... + // if (!NT_SUCCESS(RC = Ext2ObtainRegistryValues(RegistryPath))) { + // in your commercial driver implementation, it would be + // advisable for your driver to print an appropriate error + // message to the system error log before leaving + // try_return(RC); + // } + + // we should have the registry data (if any), allocate zone memory ... + // This is an example of when FSD implementations try to pre-allocate + // some fixed amount of memory to avoid internal fragmentation and/or waiting + // later during run-time ... + +#ifdef USE_ZONES + + if (!NT_SUCCESS(RC = Ext2InitializeZones())) + { + // we failed, print a message and leave ... + try_return(RC); + } +#endif + + // + // Initialize the Thread queue structure... + // + KeInitializeEvent( + &Ext2GlobalData.ThreadQueue.QueueEvent, + SynchronizationEvent, + FALSE + ); + KeInitializeSpinLock( &Ext2GlobalData.ThreadQueue.SpinLock ); + InitializeListHead( &Ext2GlobalData.ThreadQueue.ThreadQueueListHead ); + + // + // Done Initializing... + // Now Creating a worker thread to handle Worker threads... + // + PsCreateSystemThread( + &Ext2GlobalData.ThreadQueue.QueueHandlerThread, (ACCESS_MASK) 0L, + NULL, NULL, NULL, Ext2QueueHandlerThread, NULL ); + + // initialize the IRP major function table, and the fast I/O table + Ext2FsdInitializeFunctionPointers(DriverObject); + + // create a device object representing the driver itself + // so that requests can be targeted to the driver ... + // e.g. for a disk-based FSD, "mount" requests will be sent to + // this device object by the I/O Manager.\ + // For a redirector/server, you may have applications + // send "special" IOCTL's using this device object ... + RtlInitUnicodeString(&DriverDeviceName, EXT2_FS_NAME); + if (!NT_SUCCESS(RC = IoCreateDevice( + DriverObject, // our driver object + 0, // don't need an extension for this object + &DriverDeviceName,// name - can be used to "open" the driver + // see the book for alternate choices + FILE_DEVICE_DISK_FILE_SYSTEM, + 0, // no special characteristics + // do not want this as an exclusive device, though you might + FALSE, + &(Ext2GlobalData.Ext2DeviceObject)))) + { + // failed to create a device object, leave ... + try_return(RC); + } + + + + // register the driver with the I/O Manager, pretend as if this is + // a physical disk based FSD (or in order words, this FSD manages + // logical volumes residing on physical disk drives) + IoRegisterFileSystem(Ext2GlobalData.Ext2DeviceObject); + + { + TIME_FIELDS TimeFields; + + TimeFields.Day = 1; + TimeFields.Hour = 0; + TimeFields.Milliseconds = 0; + TimeFields.Minute = 0; + TimeFields.Month = 1; + TimeFields.Second = 0; + TimeFields.Weekday = 0; + TimeFields.Year = 1970; + RtlTimeFieldsToTime( &TimeFields, &Ext2GlobalData.TimeDiff ); + + /* + Ext2GlobalData.TimeDiff.QuadPart = 0; + RtlTimeToTimeFields( &Ext2GlobalData.TimeDiff,&TimeFields ); + TimeFields.Year = 2002; + RtlTimeFieldsToTime( &TimeFields, &Ext2GlobalData.TimeDiff ); + */ + + } + } + except (EXCEPTION_EXECUTE_HANDLER) + { + // we encountered an exception somewhere, eat it up + RC = GetExceptionCode(); + } + + try_exit: NOTHING; + } + finally + { + // start unwinding if we were unsuccessful + if (!NT_SUCCESS(RC)) + { + + // Now, delete any device objects, etc. we may have created + if (Ext2GlobalData.Ext2DeviceObject) + { + IoDeleteDevice(Ext2GlobalData.Ext2DeviceObject); + Ext2GlobalData.Ext2DeviceObject = NULL; + } + + // free up any memory we might have reserved for zones/lookaside + // lists + if (Ext2GlobalData.Ext2Flags & EXT2_DATA_FLAGS_ZONES_INITIALIZED) + { + Ext2DestroyZones(); + } + + // delete the resource we may have initialized + if (Ext2GlobalData.Ext2Flags & EXT2_DATA_FLAGS_RESOURCE_INITIALIZED) + { + // un-initialize this resource + ExDeleteResourceLite(&(Ext2GlobalData.GlobalDataResource)); + Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_RESOURCE_INITIALIZED); + } + } + } + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2FsdInitializeFunctionPointers() +* +* Description: +* Initialize the IRP... function pointer array in the driver object +* structure. Also initialize the fast-io function ptr array ... +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2FsdInitializeFunctionPointers( +PDRIVER_OBJECT DriverObject) // created by the I/O sub-system +{ + PFAST_IO_DISPATCH PtrFastIoDispatch = NULL; + + // initialize the function pointers for the IRP major + // functions that this FSD is prepared to handle ... + // NT Version 4.0 has 28 possible functions that a + // kernel mode driver can handle. + // NT Version 3.51 and before has only 22 such functions, + // of which 18 are typically interesting to most FSD's. + + // The only interesting new functions that a FSD might + // want to respond to beginning with Version 4.0 are the + // IRP_MJ_QUERY_QUOTA and the IRP_MJ_SET_QUOTA requests. + + // The code below does not handle quota manipulation, neither + // does the NT Version 4.0 operating system (or I/O Manager). + // However, you should be on the lookout for any such new + // functionality that your FSD might have to implement in + // the near future. + + DriverObject->MajorFunction[IRP_MJ_CREATE] = Ext2Create; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = Ext2Close; + DriverObject->MajorFunction[IRP_MJ_READ] = Ext2Read; + DriverObject->MajorFunction[IRP_MJ_WRITE] = Ext2Write; + + DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = Ext2FileInfo; + DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = Ext2FileInfo; + + DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = Ext2Flush; + // To implement support for querying and modifying volume attributes + // (volume information query/set operations), enable initialization + // of the following two function pointers and then implement the supporting + // functions. Use Chapter 11 in the text to assist you in your efforts. + DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = Ext2QueryVolInfo; + DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = Ext2SetVolInfo; + DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = Ext2DirControl; + // To implement support for file system IOCTL calls, enable initialization + // of the following function pointer and implement appropriate support. Use + // Chapter 11 in the text to assist you in your efforts. + DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = Ext2FileSystemControl; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Ext2DeviceControl; + DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = Ext2Shutdown; + // For byte-range lock support, enable initialization of the following + // function pointer and implement appropriate support. Use Chapter 10 + // in the text to assist you in your efforts. + // DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = Ext2LockControl; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = Ext2Cleanup; + // If your FSD supports security attributes, you should provide appropriate + // dispatch entry points and initialize the function pointers as given below. + // DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = Ext2Security; + // DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = Ext2Security; + // If you support extended attributes, you should provide appropriate + // dispatch entry points and initialize the function pointers as given below. + // DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = Ext2ExtendedAttr; + // DriverObject->MajorFunction[IRP_MJ_SET_EA] = Ext2ExtendedAttr; + + // Now, it is time to initialize the fast-io stuff ... +/* + DriverObject->FastIoDispatch = NULL; + +*/ + PtrFastIoDispatch = DriverObject->FastIoDispatch = &(Ext2GlobalData.Ext2FastIoDispatch); + + // initialize the global fast-io structure + // NOTE: The fast-io structure has undergone a substantial revision + // in Windows NT Version 4.0. The structure has been extensively expanded. + // Therefore, if your driver needs to work on both V3.51 and V4.0+, + // you will have to be able to distinguish between the two versions at compile time. + PtrFastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); + PtrFastIoDispatch->FastIoCheckIfPossible = Ext2FastIoCheckIfPossible; + PtrFastIoDispatch->FastIoRead = Ext2FastIoRead; + PtrFastIoDispatch->FastIoWrite = Ext2FastIoWrite; + PtrFastIoDispatch->FastIoQueryBasicInfo = Ext2FastIoQueryBasicInfo; + PtrFastIoDispatch->FastIoQueryStandardInfo = Ext2FastIoQueryStdInfo; + PtrFastIoDispatch->FastIoLock = Ext2FastIoLock; + PtrFastIoDispatch->FastIoUnlockSingle = Ext2FastIoUnlockSingle; + PtrFastIoDispatch->FastIoUnlockAll = Ext2FastIoUnlockAll; + PtrFastIoDispatch->FastIoUnlockAllByKey = Ext2FastIoUnlockAllByKey; + PtrFastIoDispatch->AcquireFileForNtCreateSection = Ext2FastIoAcqCreateSec; + PtrFastIoDispatch->ReleaseFileForNtCreateSection = Ext2FastIoRelCreateSec; + + // the remaining are only valid under NT Version 4.0 and later +#if(_WIN32_WINNT >= 0x0400) + PtrFastIoDispatch->FastIoQueryNetworkOpenInfo = Ext2FastIoQueryNetInfo; + PtrFastIoDispatch->AcquireForModWrite = Ext2FastIoAcqModWrite; + PtrFastIoDispatch->ReleaseForModWrite = Ext2FastIoRelModWrite; + PtrFastIoDispatch->AcquireForCcFlush = Ext2FastIoAcqCcFlush; + PtrFastIoDispatch->ReleaseForCcFlush = Ext2FastIoRelCcFlush; + + // MDL functionality + PtrFastIoDispatch->MdlRead = Ext2FastIoMdlRead; + PtrFastIoDispatch->MdlReadComplete = Ext2FastIoMdlReadComplete; + PtrFastIoDispatch->PrepareMdlWrite = Ext2FastIoPrepareMdlWrite; + PtrFastIoDispatch->MdlWriteComplete = Ext2FastIoMdlWriteComplete; + + // although this FSD does not support compressed read/write functionality, + // NTFS does, and if you design a FSD that can provide such functionality, + // you should consider initializing the fast io entry points for reading + // and/or writing compressed data ... +#endif // (_WIN32_WINNT >= 0x0400) + + + // last but not least, initialize the Cache Manager callback functions + // which are used in CcInitializeCacheMap() + Ext2GlobalData.CacheMgrCallBacks.AcquireForLazyWrite = Ext2AcqLazyWrite; + Ext2GlobalData.CacheMgrCallBacks.ReleaseFromLazyWrite = Ext2RelLazyWrite; + Ext2GlobalData.CacheMgrCallBacks.AcquireForReadAhead = Ext2AcqReadAhead; + Ext2GlobalData.CacheMgrCallBacks.ReleaseFromReadAhead = Ext2RelReadAhead; + + return; +} + + +VOID Ext2QueueHandlerThread( + IN PVOID StartContext ) +{ + + DebugTrace(DEBUG_TRACE_MISC, "Ext2QueueHandlerThread!!!", 0); + + while( 1 ) + { + KeWaitForSingleObject( &Ext2GlobalData.ThreadQueue.QueueEvent, + Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + + DebugTrace(DEBUG_TRACE_MISC, "Ext2QueueHandlerThread Alerted!!!", 0); + + while( !IsListEmpty( &Ext2GlobalData.ThreadQueue.ThreadQueueListHead ) ) + { + HANDLE ThreadHandle; + PLIST_ENTRY PtrEntry = NULL; + PtrExt2IrpContext PtrIrpContext = NULL; + + + PtrEntry = ExInterlockedRemoveHeadList( + &Ext2GlobalData.ThreadQueue.ThreadQueueListHead, + &Ext2GlobalData.ThreadQueue.SpinLock ); + ASSERT( PtrEntry ); + PtrIrpContext = CONTAINING_RECORD( PtrEntry, Ext2IrpContext, ThreadQueueListEntry ); + + PsCreateSystemThread( + &ThreadHandle, (ACCESS_MASK) 0L, + NULL, NULL, NULL, Ext2CommonDispatch, PtrIrpContext ); + } + } +} diff --git a/reactos/drivers/filesystems/ext2/src/fastio.c b/reactos/drivers/filesystems/ext2/src/fastio.c new file mode 100644 index 00000000000..39d87839d92 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/fastio.c @@ -0,0 +1,1757 @@ +/************************************************************************* +* +* File: fastio.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the various "fast-io" calls. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_FAST_IO + + + +/************************************************************************* +* +* Function: Ext2FastIoCheckIfPossible() +* +* Description: +* To fast-io or not to fast-io, that is the question ... +* This routine helps the I/O Manager determine whether the FSD wishes +* to permit fast-io on a specific file stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoCheckIfPossible( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +IN BOOLEAN CheckForReadOperation, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + LARGE_INTEGER IoLength; + + // Obtain a pointer to the FCB and CCB for the file stream. + PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoCheckIfPossible - Denying", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + AssertFCBorVCB( PtrFCB ); + +/* if( !( PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB + || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + + return FALSE; + } +*/ + + return FALSE; + + // Validate that this is a fast-IO request to a regular file. + // The sample FSD for example, will not allow fast-IO requests + // to volume objects, or to directories. + if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || + (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) + { + // This is not allowed. + return(ReturnedStatus); + } + + IoLength = RtlConvertUlongToLargeInteger(Length); + + // Your FSD can determine the checks that it needs to perform. + // Typically, a FSD will check whether there exist any byte-range + // locks that would prevent a fast-IO operation from proceeding. + + // ... (FSD specific checks go here). + + if (CheckForReadOperation) + { + // Chapter 11 describes how to use the FSRTL package for byte-range + // lock requests. The following routine is exported by the FSRTL + // package and it returns TRUE if the read operation should be + // allowed to proceed based on the status of the current byte-range + // locks on the file stream. If you do not use the FSRTL package + // for byte-range locking support, then you must substitute your + // own checks over here. + // ReturnedStatus = FsRtlFastCheckLockForRead(&(PtrFCB->FCBByteRangeLock), + // FileOffset, &IoLength, LockKey, FileObject, + // PsGetCurrentProcess()); + } + else + { + // This is a write request. Invoke the FSRTL byte-range lock package + // to see whether the write should be allowed to proceed. + // ReturnedStatus = FsRtlFastCheckLockForWrite(&(PtrFCB->FCBByteRangeLock), + // FileOffset, &IoLength, LockKey, FileObject, + // PsGetCurrentProcess()); + } + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoRead() +* +* Description: +* Bypass the traditional IRP method to perform a read operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +OUT PVOID Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRead", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + + try + { + + try + { + + // Chapter 11 describes how to roll your own fast-IO entry points. + // Typically, you will acquire appropriate resources here and + // then (maybe) forward the request to FsRtlCopyRead(). + // If you are a suitably complex file system, you may even choose + // to do some pre-processing (e.g. prefetching data from someplace) + // before passing on the request to the FSRTL package. + + // Of course, you also have the option of bypassing the FSRTL + // package completely and simply forwarding the request directly + // to the NT Cache Manager. + + // Bottom line is that you have complete flexibility on determining + // what you decide to do here. Read Chapter 11 well (and obviously + // other related issues) before filling in this and other fast-IO + // dispatch entry points. + + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + + } + + try_exit: NOTHING; + + } finally { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoWrite() +* +* Description: +* Bypass the traditional IRP method to perform a write operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN BOOLEAN Wait, +IN ULONG LockKey, +OUT PVOID Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoWrite", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + try + { + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoQueryBasicInfo() +* +* Description: +* Bypass the traditional IRP method to perform a query basic +* information operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoQueryBasicInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_BASIC_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoQueryBasicInfo", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + +/************************************************************************* +* +* Function: Ext2FastIoQueryStdInfo() +* +* Description: +* Bypass the traditional IRP method to perform a query standard +* information operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoQueryStdInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_STANDARD_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoQueryStdInfo", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + +/************************************************************************* +* +* Function: Ext2FastIoLock() +* +* Description: +* Bypass the traditional IRP method to perform a byte range lock +* operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoLock( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN PLARGE_INTEGER Length, +PEPROCESS ProcessId, +ULONG Key, +BOOLEAN FailImmediately, +BOOLEAN ExclusiveLock, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoLock", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoUnlockSingle() +* +* Description: +* Bypass the traditional IRP method to perform a byte range unlock +* operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoUnlockSingle( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN PLARGE_INTEGER Length, +PEPROCESS ProcessId, +ULONG Key, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockSingle", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoUnlockAll() +* +* Description: +* Bypass the traditional IRP method to perform multiple byte range unlock +* operations. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoUnlockAll( +IN PFILE_OBJECT FileObject, +PEPROCESS ProcessId, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockAll", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoUnlockAllByKey() +* +* Description: +* Bypass the traditional IRP method to perform multiple byte range unlock +* operations. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoUnlockAllByKey( +IN PFILE_OBJECT FileObject, +PEPROCESS ProcessId, +ULONG Key, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockAllByKey", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoAcqCreateSec() +* +* Description: +* Not really a fast-io operation. Used by the VMM to acquire FSD resources +* before processing a file map (create section object) request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None (we must be prepared to handle VMM initiated calls) +* +*************************************************************************/ +void Ext2FastIoAcqCreateSec( +IN PFILE_OBJECT FileObject) +{ + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // Obtain a pointer to the FCB and CCB for the file stream. + PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + + AssertFCB( PtrFCB ); + +/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + return; + } */ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoAcqCreateSec", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + // Acquire the MainResource exclusively for the file stream + + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [FastIo]", 0); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); + + DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); + + // Although this is typically not required, the sample FSD will + // also acquire the PagingIoResource exclusively at this time + // to conform with the resource acquisition described in the set + // file information routine. Once again though, you will probably + // not need to do this. + DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCBPaging Exclusively [FastIo]", 0); + DebugTraceState( "FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), TRUE); + + DebugTrace(DEBUG_TRACE_MISC,"*** FCBPaging acquired [FastIo]", 0); + + return; +} + + +/************************************************************************* +* +* Function: Ext2FastIoRelCreateSec() +* +* Description: +* Not really a fast-io operation. Used by the VMM to release FSD resources +* after processing a file map (create section object) request. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2FastIoRelCreateSec( +IN PFILE_OBJECT FileObject) +{ + + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // Obtain a pointer to the FCB and CCB for the file stream. + PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + AssertFCB( PtrFCB ); + +/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + return; + }*/ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoRelCreateSec", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + // Release the PagingIoResource for the file stream + Ext2ReleaseResource(&(PtrReqdFCB->PagingIoResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Released in [FastIo]", 0); + DebugTraceState( "FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", + PtrReqdFCB->PagingIoResource.ActiveCount, + PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, + PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + + // Release the MainResource for the file stream + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + return; +} + + +/************************************************************************* +* +* Function: Ext2AcqLazyWrite() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a delayed write (write behind/lazy write) +* operation. +* NOTE: this function really must succeed since the Cache Manager will +* typically ignore failure and continue on ... +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well) +* +*************************************************************************/ +BOOLEAN Ext2AcqLazyWrite( +IN PVOID Context, +IN BOOLEAN Wait) +{ + BOOLEAN ReturnedStatus = TRUE; + + PtrExt2VCB PtrVCB = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the sample FSD + // implementation, this context is a pointer to the CCB structure. + + ASSERT(Context); + PtrCCB = (PtrExt2CCB)(Context); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2AcqLazyWrite", 0); + + if(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB) + { + // + // Acquiring Resource for a file write... + // + PtrFCB = PtrCCB->PtrFCB; + AssertFCB( PtrFCB ); + } + else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) + { + // + // Acquiring Resource for a volume write... + // + PtrVCB = ( PtrExt2VCB )PtrCCB; + PtrCCB = NULL; + DebugTrace(DEBUG_TRACE_MISC,"~~~[FastIO call]~~~ Ext2AcqLazyWrite - for Volume", 0); + + // Acquire nothing... + // Just proceed... + return TRUE; + + } + else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) + { + // + // This must have been a FCB created / maintained on the FSD's initiative... + // This would have been done to cache access to a directory... + // + PtrFCB = ( PtrExt2FCB )PtrCCB; + PtrCCB = NULL; + } + else + { + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Ext2AcqLazyWrite - Invalid context", 0); + Ext2BreakPoint(); + return FALSE; + } + + if( PtrCCB && PtrCCB->PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); + } + + AssertFCB( PtrFCB ); + + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + + // Acquire the MainResource in the FCB exclusively. Then, set the + // lazy-writer thread id in the FCB structure for identification when + // an actual write request is received by the FSD. + // Note: The lazy-writer typically always supplies WAIT set to TRUE. + + DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCB Exclusively [FastIo]", 0); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), + Wait)) + { + DebugTrace(DEBUG_TRACE_MISC,"*** Attempt to acquire FCB FAILED [FastIo]", 0); + ReturnedStatus = FALSE; + } + else + { + DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); + // Now, set the lazy-writer thread id. + ASSERT(!(PtrFCB->LazyWriterThreadID)); + PtrFCB->LazyWriterThreadID = (unsigned int)(PsGetCurrentThread()); + } + + // If your FSD needs to perform some special preparations in anticipation + // of receving a lazy-writer request, do so now. + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2RelLazyWrite() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to release FSD +* resources after performing a delayed write (write behind/lazy write) +* operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2RelLazyWrite( +IN PVOID Context) +{ + + BOOLEAN ReturnedStatus = TRUE; + + PtrExt2VCB PtrVCB = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the sample FSD + // implementation, this context is a pointer to the CCB structure. + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2RelLazyWrite", 0); + + ASSERT(Context); + PtrCCB = (PtrExt2CCB)(Context); + + if(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB) + { + PtrFCB = PtrCCB->PtrFCB; + AssertFCB( PtrFCB ); + } + else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) + { + PtrVCB = ( PtrExt2VCB )PtrCCB; + PtrCCB = NULL; + DebugTrace(DEBUG_TRACE_MISC,"~~~[FastIO call]~~~ Ext2RelLazyWrite - for Volume", 0); + + // Acquire was acquired nothing... + // Just return... + return; + + } + else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) + { + // + // This must have been a FCB created / maintained on the FSD's initiative... + // This would have been done to cache access to a directory... + // + PtrFCB = ( PtrExt2FCB )PtrCCB; + PtrCCB = NULL; + } + else + { + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Ext2RelLazyWrite - Invalid context", 0); + Ext2BreakPoint(); + return ; + } + + if( PtrCCB && PtrCCB->PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Remove the current thread-id from the FCB and release the MainResource. + ASSERT( (PtrFCB->LazyWriterThreadID) == (unsigned int)PsGetCurrentThread() ); + PtrFCB->LazyWriterThreadID = 0; + + + // Release the acquired resource. + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + // + // Undo whatever else seems appropriate at this time... + // + + return; +} + + +/************************************************************************* +* +* Function: Ext2AcqReadAhead() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a read-ahead operation. +* NOTE: this function really must succeed since the Cache Manager will +* typically ignore failure and continue on ... +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well) +* +*************************************************************************/ +BOOLEAN Ext2AcqReadAhead( +IN PVOID Context, +IN BOOLEAN Wait) +{ + + BOOLEAN ReturnedStatus = TRUE; + + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the sample FSD + // implementation, this context is a pointer to the CCB structure. + + ASSERT(Context); + PtrCCB = (PtrExt2CCB)(Context); + ASSERT(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2AcqReadAhead", 0); + if( PtrCCB && PtrCCB->PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); + } + + PtrFCB = PtrCCB->PtrFCB; + ASSERT(PtrFCB); + + AssertFCB( PtrFCB ); +/* + if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + return TRUE; + } */ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Acquire the MainResource in the FCB shared. + // Note: The read-ahead thread typically always supplies WAIT set to TRUE. + DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCB Shared [FastIo]", 0); + + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), Wait)) + { + DebugTrace(DEBUG_TRACE_MISC,"*** Attempt to acquire FCB FAILED [FastIo]", 0); + ReturnedStatus = FALSE; + } + else + { + DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); + } + + // If your FSD needs to perform some special preparations in anticipation + // of receving a read-ahead request, do so now. + + return ReturnedStatus; + +} + + + +/************************************************************************* +* +* Function: Ext2RelReadAhead() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to release FSD +* resources after performing a read-ahead operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2RelReadAhead( +IN PVOID Context) +{ + BOOLEAN ReturnedStatus = TRUE; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + + + // The context is whatever we passed to the Cache Manager when invoking + // the CcInitializeCacheMaps() function. In the case of the sample FSD + // implementation, this context is a pointer to the CCB structure. + + ASSERT(Context); + PtrCCB = (PtrExt2CCB)(Context); + ASSERT(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); + + PtrFCB = PtrCCB->PtrFCB; + + AssertFCB( PtrFCB ); + + // ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2RelReadAhead", 0); + if( PtrCCB && PtrCCB->PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); + } + +/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + // Ext2BreakPoint(); + DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); + return; + } */ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + + // Release the acquired resource. + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + // Of course, your FSD should undo whatever else seems appropriate at this + // time. + + return; +} + + +/* the remaining are only valid under NT Version 4.0 and later */ +#if(_WIN32_WINNT >= 0x0400) + + +/************************************************************************* +* +* Function: Ext2FastIoQueryNetInfo() +* +* Description: +* Get information requested by a redirector across the network. This call +* will originate from the LAN Manager server. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoQueryNetInfo( +IN PFILE_OBJECT FileObject, +IN BOOLEAN Wait, +OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoQueryNetInfo", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoMdlRead() +* +* Description: +* Bypass the traditional IRP method to perform a MDL read operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoMdlRead( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL *MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlRead", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoMdlReadComplete() +* +* Description: +* Bypass the traditional IRP method to inform the NT Cache Manager and the +* FSD that the caller no longer requires the data locked in the system cache +* or the MDL to stay around anymore .. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoMdlReadComplete( +IN PFILE_OBJECT FileObject, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlReadComplete", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoPrepareMdlWrite() +* +* Description: +* Bypass the traditional IRP method to prepare for a MDL write operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoPrepareMdlWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +IN ULONG Length, +IN ULONG LockKey, +OUT PMDL *MdlChain, +OUT PIO_STATUS_BLOCK IoStatus, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoPrepareMdlWrite", 0); + if( FileObject ) + { + DebugTrace( DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoMdlWriteComplete() +* +* Description: +* Bypass the traditional IRP method to inform the NT Cache Manager and the +* FSD that the caller has updated the contents of the MDL. This data can +* now be asynchronously written out to secondary storage by the Cache Mgr. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: TRUE/FALSE +* +*************************************************************************/ +BOOLEAN Ext2FastIoMdlWriteComplete( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER FileOffset, +OUT PMDL MdlChain, +IN PDEVICE_OBJECT DeviceObject) +{ + BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlWriteComplete", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + + try + { + + // See description in Ext2FastIoRead() before filling-in the + // stub here. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(ReturnedStatus); +} + + +/************************************************************************* +* +* Function: Ext2FastIoAcqModWrite() +* +* Description: +* Not really a fast-io operation. Used by the VMM to acquire FSD resources +* before initiating a write operation via the Modified Page/Block Writer. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (try not to return an error, will 'ya ? :-) +* +*************************************************************************/ +NTSTATUS Ext2FastIoAcqModWrite( +IN PFILE_OBJECT FileObject, +IN PLARGE_INTEGER EndingOffset, +OUT PERESOURCE *ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoAcqModWrite", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + + // You must determine which resource(s) you would like to + // acquire at this time. You know that a write is imminent; + // you will probably therefore acquire appropriate resources + // exclusively. + + // You must first get the FCB and CCB pointers from the file object + // that is passed in to this function (as an argument). Note that + // the ending offset (when examined in conjunction with current valid data + // length) may help you in determining the appropriate resource(s) to acquire. + + // For example, if the ending offset is beyond current valid data length, + // you may decide to acquire *both* the MainResource and the PagingIoResource + // exclusively; otherwise, you may decide simply to acquire the PagingIoResource. + + // Consult the text for more information on synchronization in FSDs. + + // One final note; the VMM expects that you will return a pointer to + // the resource that you acquired (single return value). This pointer + // will be returned back to you in the release call (below). + + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2FastIoRelModWrite() +* +* Description: +* Not really a fast-io operation. Used by the VMM to release FSD resources +* after processing a modified page/block write operation. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error (an error returned here is really not expected!) +* +*************************************************************************/ +NTSTATUS Ext2FastIoRelModWrite( +IN PFILE_OBJECT FileObject, +IN PERESOURCE ResourceToRelease, +IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace( DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRelModWrite", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + + // The MPW has complete the write for modified pages and therefore + // wants you to release pre-acquired resource(s). + + // You must undo here whatever it is that you did in the + // Ext2FastIoAcqModWrite() call above. + + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2FastIoAcqCcFlush() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a CcFlush() operation on a specific file +* stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2FastIoAcqCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoAcqCcFlush", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + // Acquire appropriate resources that will allow correct synchronization + // with a flush call (and avoid deadlock). + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2FastIoRelCcFlush() +* +* Description: +* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD +* resources before performing a CcFlush() operation on a specific file +* stream. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2FastIoRelCcFlush( +IN PFILE_OBJECT FileObject, +IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + + FsRtlEnterFileSystem(); + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRelCcFlush", 0); + if( FileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); + } + + try + { + try + { + // Release resources acquired in Ext2FastIoAcqCcFlush() above. + NOTHING; + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, NULL); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + try_exit: NOTHING; + + } + finally + { + + } + + FsRtlExitFileSystem(); + + return(RC); +} + +#endif //_WIN32_WINNT >= 0x0400 diff --git a/reactos/drivers/filesystems/ext2/src/fileinfo.c b/reactos/drivers/filesystems/ext2/src/fileinfo.c new file mode 100644 index 00000000000..0047d50f23f --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/fileinfo.c @@ -0,0 +1,1125 @@ +/************************************************************************* +* +* File: fileinfo.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "set/query file information" dispatch +* entry points. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_INFORMATION +#define DEBUG_LEVEL (DEBUG_TRACE_FILEINFO) + + +/************************************************************************* +* +* Function: Ext2FileInfo() +* +* Description: +* The I/O Manager will invoke this routine to handle a set/query file +* information request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2FileInfo( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "File Info Control IRP received...", 0); + + FsRtlEnterFileSystem(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonFileInfo(PtrIrpContext, Irp); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2CommonFileInfo() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonFileInfo( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + BOOLEAN MainResourceAcquired = FALSE; + BOOLEAN VCBResourceAcquired = FALSE; + BOOLEAN PagingIoResourceAcquired = FALSE; + IO_STATUS_BLOCK LocalIoStatus; + void *PtrSystemBuffer = NULL; + long BufferLength = 0; + FILE_INFORMATION_CLASS FunctionalityRequested; + BOOLEAN CanWait = FALSE; + BOOLEAN PostRequest = FALSE; + + try + { + // First, get a pointer to the current I/O stack location. + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Get the FCB and CCB pointers + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + + // If the caller has opened a logical volume and is attempting to + // query information for it as a file stream, return an error. + if (PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) + { + // This is not allowed. Caller must use get/set volume information instead. + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB); + AssertFCB( PtrFCB ); + + PtrSystemBuffer = PtrIrp->AssociatedIrp.SystemBuffer; + + if (PtrIoStackLocation->MajorFunction == IRP_MJ_QUERY_INFORMATION) + { + // *********************** + // Query File Information + // *********************** + + // Now, obtain some parameters. + DebugTrace(DEBUG_TRACE_MISC, "Buffer length = 0x%lX[FileInfo]", BufferLength ); + + BufferLength = PtrIoStackLocation->Parameters.QueryFile.Length; + + FunctionalityRequested = PtrIoStackLocation->Parameters.QueryFile.FileInformationClass; + + // Read in the file inode if it hasn't already been read... + Ext2InitializeFCBInodeInfo( PtrFCB ); + + // + // Acquire the MainResource shared + // except for page files... + // + if (!(PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE)) + { + // Acquire the MainResource shared. + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared [FileInfo]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquisition FAILED [FileInfo]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [FileInfo]", 0); + } + + // Do whatever the caller asked us to do + switch (FunctionalityRequested) + { + case FileBasicInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileBasicInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2GetBasicInformation(PtrFCB, (PFILE_BASIC_INFORMATION)PtrSystemBuffer, &BufferLength); + break; + case FileStandardInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileStandardInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2GetStandardInformation(PtrFCB, (PFILE_STANDARD_INFORMATION)PtrSystemBuffer, &BufferLength); + break; + // Similarly, implement all of the other query information routines + // that your FSD can support. +#if(_WIN32_WINNT >= 0x0400) + case FileNetworkOpenInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileNetworkOpenInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2GetNetworkOpenInformation(PtrFCB, (PFILE_NETWORK_OPEN_INFORMATION)PtrSystemBuffer, &BufferLength); + // RC = STATUS_INVALID_PARAMETER; + // try_return(RC); + break; +#endif // _WIN32_WINNT >= 0x0400 + case FileInternalInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileInternalInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // RC = Ext2GetInternalInformation(...); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + break; + case FileEaInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileEaInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + { + PFILE_EA_INFORMATION EaInformation; + EaInformation = (PFILE_EA_INFORMATION) PtrSystemBuffer; + EaInformation->EaSize = 0; + BufferLength = sizeof( FILE_EA_INFORMATION ); + break; + } + // RC = Ext2GetEaInformation(...); + break; + + case FilePositionInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FilePositionInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // This is fairly simple. Copy over the information from the + // file object. + { + PFILE_POSITION_INFORMATION PtrFileInfoBuffer; + + PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer; + + ASSERT(BufferLength >= sizeof(FILE_POSITION_INFORMATION)); + PtrFileInfoBuffer->CurrentByteOffset = PtrFileObject->CurrentByteOffset; + // Modify the local variable for BufferLength appropriately. + BufferLength = sizeof(FILE_POSITION_INFORMATION); + } + break; + case FileStreamInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileStreamInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // RC = Ext2GetFileStreamInformation(...); + + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + + break; + case FileAllInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileAllInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // The I/O Manager supplies the Mode, Access, and Alignment + // information. The rest is up to us to provide. + // Therefore, decrement the BufferLength appropriately (assuming + // that the above 3 types on information are already in the + // buffer) + { + + PFILE_POSITION_INFORMATION PtrFileInfoBuffer; + PFILE_ALL_INFORMATION PtrAllInfo = (PFILE_ALL_INFORMATION)PtrSystemBuffer; + + // Fill in the position information. + + PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)&(PtrAllInfo->PositionInformation); + + PtrFileInfoBuffer->CurrentByteOffset = PtrFileObject->CurrentByteOffset; + + // Modify the local variable for BufferLength appropriately. + BufferLength = sizeof(FILE_ALL_INFORMATION); + + // Get the remaining stuff. + if (!NT_SUCCESS(RC = Ext2GetBasicInformation(PtrFCB, (PFILE_BASIC_INFORMATION)&(PtrAllInfo->BasicInformation), + &BufferLength))) + { + try_return(RC); + } + if (!NT_SUCCESS(RC = Ext2GetStandardInformation(PtrFCB, &(PtrAllInfo->StandardInformation), &BufferLength))) + { + try_return(RC); + } + // Similarly, get all of the others ... + } + break; + case FileNameInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileNameInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // RC = Ext2GetFullNameInformation(...); + RC = Ext2GetFullNameInformation(PtrFCB, PtrCCB, (PFILE_NAME_INFORMATION)PtrSystemBuffer, &BufferLength); + break; + case FileAlternateNameInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileAlternateNameInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + // RC = Ext2GetAltNameInformation(...); + break; + case FileCompressionInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "FileCompressionInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + // RC = Ext2GetCompressionInformation(...); + break; + + default: + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + + // If we completed successfully, the return the amount of information transferred. + if (NT_SUCCESS(RC)) + { + PtrIrp->IoStatus.Information = BufferLength; + } + else + { + PtrIrp->IoStatus.Information = 0; + } + + } + else + { + // *********************** + // Set File Information + // *********************** + ASSERT(PtrIoStackLocation->MajorFunction == IRP_MJ_SET_INFORMATION); + + DebugTrace(DEBUG_TRACE_FILEINFO, ">>>>>>>> Set File Information <<<<<<<<< [FileInfo]", 0); + + + // Now, obtain some parameters. + FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass; + + // Check oplocks... + + // + // Acquire the VCB resource exclusively for + // deletion, rename and link operations... + // To synchronize with create and cleanup operations + // + if ((FunctionalityRequested == FileDispositionInformation) || + (FunctionalityRequested == FileRenameInformation) || + (FunctionalityRequested == FileLinkInformation)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [FileInfo]", 0); + DebugTraceState( " VCB AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [FileInfo]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + // We have the VCB acquired exclusively. + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired [FileInfo]", 0); + VCBResourceAcquired = TRUE; + } + + + // Acquire the FCB exclusively at this time... + if (!(PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE)) + { + // Acquire the MainResource shared. + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [FileInfo]", 0); + DebugTraceState( " FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [FileInfo]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquired [FileInfo]", 0); + } + + // + // For delete link (rename), + // set allocation size, and set EOF, should also acquire the paging-IO + // resource, thereby synchronizing with paging-IO requests. + // + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject); + + } + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCBPaging Exclusively [FileInfo]", 0); + DebugTraceState( " FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempt to acquire FCBPaging FAILED [FileInfo]", 0); + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + PagingIoResourceAcquired = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** Acquired FCBPaging [FileInfo]", 0); + + // Do whatever the caller asked us to do + switch (FunctionalityRequested) + { + case FileBasicInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileBasicInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2SetBasicInformation(PtrIrpContext, PtrFCB, PtrFileObject, (PFILE_BASIC_INFORMATION)PtrSystemBuffer); + // RC = STATUS_ACCESS_DENIED; + break; + case FileAllocationInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileAllocationInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2SetAllocationInformation(PtrFCB, PtrCCB, PtrVCB, PtrFileObject, + PtrIrpContext, PtrIrp, PtrSystemBuffer); + break; + case FileEndOfFileInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileEndOfFileInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // RC = Ext2SetEOF(...); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + break; + + case FilePositionInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FilePositionInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + // Check if no intermediate buffering has been specified. + // If it was specified, do not allow non-aligned set file + // position requests to succeed. + { + PFILE_POSITION_INFORMATION PtrFileInfoBuffer; + + PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer; + + if (PtrFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) + { + if (PtrFileInfoBuffer->CurrentByteOffset.LowPart & PtrIoStackLocation->DeviceObject->AlignmentRequirement) + { + // Invalid alignment. + try_return(RC = STATUS_INVALID_PARAMETER); + } + } + PtrFileObject->CurrentByteOffset = PtrFileInfoBuffer->CurrentByteOffset; + } + break; + + case FileDispositionInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileDispositionInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2SetDispositionInformation(PtrFCB, PtrCCB, PtrVCB, PtrFileObject, + PtrIrpContext, PtrIrp, + (PFILE_DISPOSITION_INFORMATION)PtrSystemBuffer); + break; + + case FileRenameInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileRenameInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = Ext2RenameOrLinkFile( PtrFCB, PtrFileObject, PtrIrpContext, + PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer); + break; + case FileLinkInformation: + DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileLinkInformation for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + // When you implement your rename/link routine, be careful to + // check the following two arguments: + // TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject; + // ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists; + // + // The TargetFileObject argument is a pointer to the "target + // directory" file object obtained during the "create" routine + // invoked by the NT I/O Manager with the SL_OPEN_TARGET_DIRECTORY + // flag specified. Remember that it is quite possible that if the + // rename/link is contained within a single directory, the target + // and source directories will be the same. + // The ReplaceExistingFile argument should be used by you to + // determine if the caller wishes to replace the target (if it + // currently exists) with the new link/renamed file. If this + // value is FALSE, and if the target directory entry (being + // renamed-to, or the target of the link) exists, you should + // return a STATUS_OBJECT_NAME_COLLISION error to the caller. + + // RC = Ext2RenameOrLinkFile(PtrFCB, PtrCCB, PtrFileObject, PtrIrpContext, + // PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer); + + // Once you have completed the rename/link operation, do not + // forget to notify any "notify IRPs" about the actions you have + // performed. + // An example is if you renamed across directories, you should + // report that a new entry was added with the FILE_ACTION_ADDED + // action type. The actual modification would then be reported + // as either FILE_NOTIFY_CHANGE_FILE_NAME (if a file was renamed) + // or FILE_NOTIFY_CHANGE_DIR_NAME (if a directory was renamed). + + break; + default: + DebugTrace(DEBUG_TRACE_FILEINFO, "Unrecoganised SetFileInformation code for %S", PtrFCB->FCBName->ObjectName.Buffer ); + RC = STATUS_INVALID_PARAMETER; + try_return(RC); + } + } + + try_exit: NOTHING; + } + finally + { + if (PagingIoResourceAcquired) + { + Ext2ReleaseResource(&(PtrReqdFCB->PagingIoResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Released [FileInfo]", 0); + DebugTraceState( " FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", + PtrReqdFCB->PagingIoResource.ActiveCount, + PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, + PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject); + } + + PagingIoResourceAcquired = FALSE; + } + + if (MainResourceAcquired) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FileInfo]", 0); + DebugTraceState( " FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject); + } + + MainResourceAcquired = FALSE; + } + + if (VCBResourceAcquired) + { + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [FileInfo]", 0); + DebugTraceState( " VCB AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", + PtrVCB->VCBResource.ActiveCount, + PtrVCB->VCBResource.NumberOfExclusiveWaiters, + PtrVCB->VCBResource.NumberOfSharedWaiters ); + + VCBResourceAcquired = FALSE; + } + + // Post IRP if required + if (PostRequest) + { + + // Since, the I/O Manager gave us a system buffer, we do not + // need to "lock" anything. + + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + + } + else + { + + // Can complete the IRP here if no exception was encountered + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) { + PtrIrp->IoStatus.Status = RC; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + } // can we complete the IRP ? + } // end of "finally" processing + + // DbgPrint( "\n === File Info IRP returning --> RC : 0x%lX Bytes: 0x%lX", PtrIrp->IoStatus.Status, PtrIrp->IoStatus.Information ); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2GetBasicInformation() +* +* Description: +* Return some time-stamps and file attributes to the caller. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2GetBasicInformation( +PtrExt2FCB PtrFCB, +PFILE_BASIC_INFORMATION PtrBuffer, +long *PtrReturnedLength ) +{ + NTSTATUS RC = STATUS_SUCCESS; + + try + { + if (*PtrReturnedLength < sizeof(FILE_BASIC_INFORMATION)) + { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrBuffer, sizeof(FILE_BASIC_INFORMATION)); + + // Get information from the FCB. + PtrBuffer->CreationTime = PtrFCB->CreationTime; + PtrBuffer->LastAccessTime = PtrFCB->LastAccessTime; + PtrBuffer->LastWriteTime = PtrFCB->LastWriteTime; + PtrBuffer->ChangeTime = PtrFCB->LastWriteTime; + + // Now fill in the attributes. + PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL; + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ) ) + { + // Special File... + // Treated with respect... ;) + // + PtrBuffer->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY) ; + } + + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ) ) + { + PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ) ) + { + PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + + try_exit: NOTHING; + } + finally + { + if (NT_SUCCESS(RC)) + { + // Return the amount of information filled in. + *PtrReturnedLength = sizeof(FILE_BASIC_INFORMATION); + } + } + return(RC); +} + +NTSTATUS Ext2GetStandardInformation( +PtrExt2FCB PtrFCB, + +PFILE_STANDARD_INFORMATION PtrStdInformation, +long *PtrReturnedLength ) +{ + + NTSTATUS RC = STATUS_SUCCESS; + + + try + { + if (*PtrReturnedLength < sizeof( FILE_STANDARD_INFORMATION )) + { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrStdInformation, sizeof(FILE_STANDARD_INFORMATION)); + + + PtrStdInformation->AllocationSize = PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize; + PtrStdInformation->EndOfFile = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize; + PtrStdInformation->DeletePending = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE); + PtrStdInformation->Directory = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ); + PtrStdInformation->NumberOfLinks = PtrFCB->LinkCount; + + try_exit: NOTHING; + } + finally + { + if (NT_SUCCESS(RC)) + { + // Return the amount of information filled in. + *PtrReturnedLength = sizeof( FILE_STANDARD_INFORMATION ); + } + } + return(RC); +} + +NTSTATUS Ext2GetNetworkOpenInformation( + PtrExt2FCB PtrFCB, + PFILE_NETWORK_OPEN_INFORMATION PtrNetworkOpenInformation, + long *PtrReturnedLength ) +{ + + NTSTATUS RC = STATUS_SUCCESS; + + try + { + if (*PtrReturnedLength < sizeof( FILE_NETWORK_OPEN_INFORMATION )) + { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrNetworkOpenInformation, sizeof(FILE_NETWORK_OPEN_INFORMATION)); + + PtrNetworkOpenInformation->CreationTime = PtrFCB->CreationTime; + PtrNetworkOpenInformation->LastAccessTime = PtrFCB->LastAccessTime; + PtrNetworkOpenInformation->LastWriteTime = PtrFCB->LastWriteTime; + PtrNetworkOpenInformation->ChangeTime = PtrFCB->LastWriteTime; + PtrNetworkOpenInformation->AllocationSize = PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize; + PtrNetworkOpenInformation->EndOfFile = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize; + + // Now fill in the attributes. + PtrNetworkOpenInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; + + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ) ) + { + // Special File... + // Treated with respect... ;) + // + PtrNetworkOpenInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY) ; + } + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ) ) + { + PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + + if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ) ) + { + PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + try_exit: NOTHING; + } + finally + { + if (NT_SUCCESS(RC)) + { + // Return the amount of information filled in. + *PtrReturnedLength = sizeof( FILE_NETWORK_OPEN_INFORMATION ); + } + } + return(RC); +} + + +NTSTATUS Ext2GetFullNameInformation( + PtrExt2FCB PtrFCB, + PtrExt2CCB PtrCCB, + PFILE_NAME_INFORMATION PtrNameInformation, + long *PtrReturnedLength ) +{ + + NTSTATUS RC = STATUS_SUCCESS; + + try + { + if (*PtrReturnedLength < + (long)( sizeof(FILE_NAME_INFORMATION) + PtrCCB->AbsolutePathName.Length) ) + { + try_return(RC = STATUS_BUFFER_OVERFLOW); + } + + // Zero out the supplied buffer. + RtlZeroMemory(PtrNameInformation, sizeof( FILE_NAME_INFORMATION ) ); + + if( PtrCCB->AbsolutePathName.Length ) + { + RtlCopyMemory( + PtrNameInformation->FileName, // Destination, + PtrCCB->AbsolutePathName.Buffer, // Source, + PtrCCB->AbsolutePathName.Length ); // Length + + PtrNameInformation->FileNameLength = PtrCCB->AbsolutePathName.Length; + try_return(RC = STATUS_SUCCESS); + } + else + { + try_return(RC = STATUS_INVALID_PARAMETER); + } + + try_exit: NOTHING; + } + finally + { + if (NT_SUCCESS(RC)) + { + // Return the amount of information filled in. + *PtrReturnedLength = + sizeof( FILE_NAME_INFORMATION ) + + PtrCCB->AbsolutePathName.Length; + } + } + return(RC); +} +/************************************************************************* +* +* Function: Ext2SetBasicInformation() +* +* Description: +* Set some time-stamps and file attributes supplied by the caller. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2SetBasicInformation( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + PFILE_BASIC_INFORMATION PtrFileInformation ) +{ + NTSTATUS RC = STATUS_SUCCESS; + + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + AssertVCB( PtrVCB ); + + // BOOLEAN CreationTimeChanged = FALSE; + // BOOLEAN AttributesChanged = FALSE; + +// return STATUS_INVALID_PARAMETER; + + try + { + EXT2_INODE Inode; + RtlZeroMemory(&Inode, sizeof( EXT2_INODE )); + + if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + // + // Update time stamps in the inode + // and in the FCB... + // + if( PtrFileInformation->CreationTime.QuadPart ) + { + PtrFCB->CreationTime.QuadPart = PtrFileInformation->CreationTime.QuadPart; + Inode.i_ctime = (ULONG) ( (PtrFCB->CreationTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + + } + if( PtrFileInformation->LastAccessTime.QuadPart ) + { + PtrFCB->LastAccessTime.QuadPart = PtrFileInformation->LastAccessTime.QuadPart; + Inode.i_atime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + + } + if( PtrFileInformation->LastWriteTime.QuadPart ) + { + PtrFCB->LastWriteTime.QuadPart = PtrFileInformation->LastWriteTime.QuadPart; + Inode.i_mtime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart + - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + } + + // Now come the attributes. + if (PtrFileInformation->FileAttributes) + { + if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_READONLY ) + { + // Turn off the write bits... + Ext2SetModeReadOnly( Inode.i_mode ); + } + if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_HIDDEN ) + { + // Turn off the read and write bits... + Ext2SetModeHidden( Inode.i_mode ); + + } + if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_SYSTEM ) + { + // Just turn off the read and write bits... + // No special field to indicate that this is a system file... + Ext2SetModeReadOnly( Inode.i_mode ); + Ext2SetModeHidden( Inode.i_mode ); + } + } + + // Updating the inode... + Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ); + } + + if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) + { + Ext2SetFlag(PtrFileObject->Flags, FO_TEMPORARY_FILE); + } + else + { + Ext2ClearFlag(PtrFileObject->Flags, FO_TEMPORARY_FILE); + } + + try_exit: NOTHING; + } + finally + { + ; + } + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2SetDispositionInformation() +* +* Description: +* Mark/Unmark a file for deletion. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2SetDispositionInformation( +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB, +PtrExt2VCB PtrVCB, +PFILE_OBJECT PtrFileObject, +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PFILE_DISPOSITION_INFORMATION PtrBuffer) +{ + NTSTATUS RC = STATUS_SUCCESS; + + try + { + if (!PtrBuffer->DeleteFile) + { + // "un-delete" the file. + Ext2ClearFlag(PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE); + PtrFileObject->DeletePending = FALSE; + try_return(RC); + } + + // Do some checking to see if the file can even be deleted. + + if (PtrFCB->FCBFlags & EXT2_FCB_DELETE_ON_CLOSE) + { + // All done! + try_return(RC); + } + + if (PtrFCB->FCBFlags & EXT2_FCB_READ_ONLY) + { + try_return(RC = STATUS_CANNOT_DELETE); + } + + if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_READ_ONLY) + { + try_return(RC = STATUS_CANNOT_DELETE); + } + + // An important step is to check if the file stream has been + // mapped by any process. The delete cannot be allowed to proceed + // in this case. + if (!MmFlushImageSection(&(PtrFCB->NTRequiredFCB.SectionObject), MmFlushForDelete)) + { + try_return(RC = STATUS_CANNOT_DELETE); + } + + // Disallow deletion of either a root + // directory or a directory that is not empty. + if( PtrFCB->INodeNo == EXT2_ROOT_INO ) + { + try_return(RC = STATUS_CANNOT_DELETE); + } + + if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY) + { + if (!Ext2IsDirectoryEmpty(PtrFCB, PtrCCB, PtrIrpContext)) + { + try_return(RC = STATUS_DIRECTORY_NOT_EMPTY); + } + } + + // Set a flag to indicate that this directory entry will become history + // at cleanup. + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE); + PtrFileObject->DeletePending = TRUE; + + try_exit: NOTHING; + } + finally + { + ; + } + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2SetAllocationInformation() +* +* Description: +* Mark/Unmark a file for deletion. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2SetAllocationInformation( +PtrExt2FCB PtrFCB, +PtrExt2CCB PtrCCB, +PtrExt2VCB PtrVCB, +PFILE_OBJECT PtrFileObject, +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PFILE_ALLOCATION_INFORMATION PtrBuffer) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN TruncatedFile = FALSE; + BOOLEAN ModifiedAllocSize = FALSE; + + try + { + + // Are we increasing the allocation size? + if (RtlLargeIntegerLessThan( + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize, + PtrBuffer->AllocationSize)) + { + ULONG CurrentSize; + ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + for( CurrentSize = 0; CurrentSize < PtrBuffer->AllocationSize.QuadPart; CurrentSize += LogicalBlockSize ) + { + Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE ); + } + ModifiedAllocSize = TRUE; + } + else if (RtlLargeIntegerGreaterThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize, + PtrBuffer->AllocationSize)) + { + // This is the painful part. See if the VMM will allow us to proceed. + // The VMM will deny the request if: + // (a) any image section exists OR + // (b) a data section exists and the size of the user mapped view + // is greater than the new size + // Otherwise, the VMM should allow the request to proceed. + if (!MmCanFileBeTruncated(&(PtrFCB->NTRequiredFCB.SectionObject), &(PtrBuffer->AllocationSize))) + { + // VMM said no way! + try_return(RC = STATUS_USER_MAPPED_FILE); + } + + if( !Ext2TruncateFileAllocationSize( PtrIrpContext, PtrFCB, PtrFileObject, &PtrBuffer->AllocationSize) ) + { + // This will do until I figure out a better error message code ;) + RC = STATUS_INSUFFICIENT_RESOURCES; + + } + + ModifiedAllocSize = TRUE; + TruncatedFile = TRUE; + } + + try_exit: + + // This is a good place to check if we have performed a truncate + // operation. If we have perform a truncate (whether we extended + // or reduced file size), you should update file time stamps. + + // Last, but not the lease, you must inform the Cache Manager of file size changes. + if (ModifiedAllocSize && NT_SUCCESS(RC)) + { + // Update the FCB Header with the new allocation size. + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize = PtrBuffer->AllocationSize; + + // If we decreased the allocation size to less than the + // current file size, modify the file size value. + // Similarly, if we decreased the value to less than the + // current valid data length, modify that value as well. + if (TruncatedFile) + { + if (RtlLargeIntegerLessThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize, PtrBuffer->AllocationSize)) + { + // Decrease the file size value. + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize = PtrBuffer->AllocationSize; + } + + if (RtlLargeIntegerLessThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.ValidDataLength, PtrBuffer->AllocationSize)) + { + // Decrease the valid data length value. + PtrFCB->NTRequiredFCB.CommonFCBHeader.ValidDataLength = PtrBuffer->AllocationSize; + } + } + + + // If the FCB has not had caching initiated, it is still valid + // for you to invoke the NT Cache Manager. It is possible in such + // situations for the call to be no'oped (unless some user has + // mapped in the file) + + // NOTE: The invocation to CcSetFileSizes() will quite possibly + // result in a recursive call back into the file system. + // This is because the NT Cache Manager will typically + // perform a flush before telling the VMM to purge pages + // especially when caching has not been initiated on the + // file stream, but the user has mapped the file into + // the process' virtual address space. + CcSetFileSizes(PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + + // Inform any pending IRPs (notify change directory). + } + + } + finally + { + ; + } + return(RC); +} diff --git a/reactos/drivers/filesystems/ext2/src/flush.c b/reactos/drivers/filesystems/ext2/src/flush.c new file mode 100644 index 00000000000..fd25fa33899 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/flush.c @@ -0,0 +1,350 @@ +/************************************************************************* +* +* File: flush.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Flush Buffers" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_FLUSH + +#define DEBUG_LEVEL (DEBUG_TRACE_FLUSH) + + +/************************************************************************* +* +* Function: Ext2Flush() +* +* Description: +* The I/O Manager will invoke this routine to handle a flush buffers +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2Flush( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Flush IRP Received...", 0); + + // Ext2BreakPoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonFlush(PtrIrpContext, Irp); + + } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonFlush() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonFlush( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + BOOLEAN AcquiredFCB = FALSE; + BOOLEAN PostRequest = FALSE; + BOOLEAN CanWait = TRUE; + + try { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Get the FCB and CCB pointers + PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2); + ASSERT(PtrCCB); + PtrFCB = PtrCCB->PtrFCB; + AssertFCB( PtrFCB ); + + /*ASSERT(PtrFCB); + ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB );*/ + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Get some of the parameters supplied to us + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + + // If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous. + if (!CanWait) { + PostRequest = TRUE; + try_return(RC); + } + + // Check the type of object passed-in. That will determine the course of + // action we take. + if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || (PtrFCB->FCBFlags & EXT2_FCB_ROOT_DIRECTORY)) { + + if (PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) { + PtrVCB = (PtrExt2VCB)(PtrFCB); + } else { + PtrVCB = PtrFCB->PtrVCB; + } + + // The caller wishes to flush all files for the mounted + // logical volume. The flush volume routine below should simply + // walk through all of the open file streams, acquire the + // FCB resource, and request the flush operation from the Cache + // Manager. Basically, the sequence of operations listed below + // for a single file should be executed on all open files. + + Ext2FlushLogicalVolume(PtrIrpContext, PtrIrp, PtrVCB); + + try_return(RC); + } + + if (!(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) + { + // This is a regular file. + ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); + AcquiredFCB = TRUE; + + // Request the Cache Manager to perform a flush operation. + // Further, instruct the Cache Manager that we wish to flush the + // entire file stream. + Ext2FlushAFile(PtrReqdFCB, &(PtrIrp->IoStatus)); + RC = PtrIrp->IoStatus.Status; + // All done. You may want to also flush the directory entry for the + // file stream at this time. + + // Some log-based FSD implementations may wish to flush their + // log files at this time. Finally, you should update the time-stamp + // values for the file stream appropriately. This would involve + // obtaining the current time and modifying the appropriate directory + // entry fields. + } + + try_exit: + + if (AcquiredFCB) + { + Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Flush]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Flush]", + PtrReqdFCB->MainResource.ActiveCount, + PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, + PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + + AcquiredFCB = FALSE; + } + + if (!PostRequest) + { + PIO_STACK_LOCATION PtrNextIoStackLocation = NULL; + NTSTATUS RC1 = STATUS_SUCCESS; + + // Send the request down at this point. + // To do this, you must set the next IRP stack location, and + // maybe set a completion routine. + // Be careful about marking the IRP pending if the lower level + // driver returned pending and you do have a completion routine! + PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp); + *PtrNextIoStackLocation = *PtrIoStackLocation; + + // Set the completion routine to "eat-up" any + // STATUS_INVALID_DEVICE_REQUEST error code returned by the lower + // level driver. + IoSetCompletionRoutine(PtrIrp, Ext2FlushCompletion, NULL, TRUE, TRUE, TRUE); + + /* + * The exception handlers propably masked out the + * fact that PtrVCB was never set. + * -- Filip Navara, 18/08/2004 + */ + PtrVCB = PtrFCB->PtrVCB; + RC1 = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); + + RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1); + } + + } finally { + if (PostRequest) { + // Nothing to lock now. + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } else { + // Release the IRP context at this time. + Ext2ReleaseIrpContext(PtrIrpContext); + } + } + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2FlushAFile() +* +* Description: +* Tell the Cache Manager to perform a flush. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2FlushAFile( +PtrExt2NTRequiredFCB PtrReqdFCB, +PIO_STATUS_BLOCK PtrIoStatus) +{ + CcFlushCache(&(PtrReqdFCB->SectionObject), NULL, 0, PtrIoStatus); + return; +} + +/************************************************************************* +* +* Function: Ext2FlushLogicalVolume() +* +* Description: +* Flush everything beginning at root directory. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2FlushLogicalVolume( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +PtrExt2VCB PtrVCB) +{ + BOOLEAN AcquiredVCB = FALSE; + PtrExt2FCB PtrFCB = NULL; + PLIST_ENTRY PtrNextFCB = NULL; + + try { + ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE); + + AcquiredVCB = TRUE; + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired Ex [Flush] ", 0); + + // Go through the list of FCB's. You would probably + // flush all of the files. Then, you could flush the + // directories that you may have have pinned into memory. + + // NOTE: This function may also be invoked internally as part of + // processing a shutdown request. + + } + finally + { + if (AcquiredVCB) + { + Ext2ReleaseResource(&(PtrVCB->VCBResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Flush]", 0); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Flush]", + PtrVCB->VCBResource.ActiveCount, + PtrVCB->VCBResource.NumberOfExclusiveWaiters, + PtrVCB->VCBResource.NumberOfSharedWaiters ); + } + } + + return; +} + + +/************************************************************************* +* +* Function: Ext2FlushCompletion() +* +* Description: +* Eat up any bad errors. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +NTSTATUS Ext2FlushCompletion( +PDEVICE_OBJECT PtrDeviceObject, +PIRP PtrIrp, +PVOID Context) +{ + NTSTATUS RC = STATUS_SUCCESS; + + if (PtrIrp->PendingReturned) { + IoMarkIrpPending(PtrIrp); + } + + if (PtrIrp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) { + // cannot do much here, can we? + PtrIrp->IoStatus.Status = STATUS_SUCCESS; + } + + return(STATUS_SUCCESS); +} diff --git a/reactos/drivers/filesystems/ext2/src/fsctrl.c b/reactos/drivers/filesystems/ext2/src/fsctrl.c new file mode 100644 index 00000000000..b25eed32ff6 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/fsctrl.c @@ -0,0 +1,944 @@ +/************************************************************************* +* +* File: fsctrl.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the various File System Control calls. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + + + +#include "ext2fsd.h" + + + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_FILE_CONTROL +#define DEBUG_LEVEL (DEBUG_TRACE_FSCTRL) + + +NTSTATUS +Ext2MountVolume( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ); + +NTSTATUS +Ext2GetPartitionInfo( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PPARTITION_INFORMATION PartitionInformation + ); + +NTSTATUS +Ext2GetDriveLayout( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation, + IN int BufferSize + ); + +BOOLEAN +Ext2PerformVerifyDiskRead( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PVOID Buffer, + IN LONGLONG Lbo, + IN ULONG NumberOfBytesToRead + ); + +NTSTATUS Ext2UserFileSystemRequest( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ); + + +/************************************************************************* +* +* Function: Ext2FileSystemControl +* +* Description: +* The I/O Manager will invoke this routine to handle a +* File System Control IRP +* +* Expected Interrupt Level (for execution) : +* +* ??? +* +* Arguments: +* +* DeviceObject - Supplies the volume device object where the +* file exists +* +* Irp - Supplies the Irp being processed +* +* +* Return Value: +* +* NTSTATUS - The FSD status for the IRP +* +*************************************************************************/ +NTSTATUS +Ext2FileSystemControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "File System Control IRP Received...", 0); + + // Ext2BreakPoint(); + + FsRtlEnterFileSystem(); + + ASSERT(DeviceObject); + ASSERT(Irp); + + // + // Get a pointer to the current Irp stack location + // + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + + if( IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) + { + DebugTrace(DEBUG_TRACE_MOUNT, "Mount Request Received...", 0); + Status = Ext2MountVolume ( Irp, IrpSp ); + Ext2CompleteRequest( Irp, Status ); + } + else if( IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST ) + { + DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_USER_FS_REQUEST received...", 0); + Status = Ext2UserFileSystemRequest( Irp, IrpSp ); + Ext2CompleteRequest( Irp, Status ); + } + else + { + if( IrpSp->MinorFunction == IRP_MN_VERIFY_VOLUME ) + { + DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_VERIFY_VOLUME received...", 0); + } + else if( IrpSp->MinorFunction == IRP_MN_LOAD_FILE_SYSTEM ) + { + DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_LOAD_FILE_SYSTEM received...", 0); + } + else + { + DebugTrace(DEBUG_TRACE_FSCTRL, "Unknown Minor IRP code received...", 0); + } + + Status = STATUS_INVALID_DEVICE_REQUEST; + Ext2CompleteRequest( Irp, Status ); + } + + FsRtlExitFileSystem(); + + return Status; +} + + + +/************************************************************************* +* +* Function: Ext2MountVolume() +* +* Description: +* This routine verifies and mounts the volume; +* Called by FSCTRL IRP handler to attempt a +* volume mount. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* +* Arguments: +* +* Irp - Supplies the Irp being processed +* IrpSp - Irp Stack Location pointer +* +* Return Value: +* +* NTSTATUS - The Mount status +* +*************************************************************************/ +NTSTATUS +Ext2MountVolume ( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ) +{ + + // Volume Parameter Block + PVPB PtrVPB; + + // The target device object + PDEVICE_OBJECT TargetDeviceObject = NULL; + + // The new volume device object (to be created if partition is Ext2) + PDEVICE_OBJECT PtrVolumeDeviceObject = NULL; + + // Return Status + NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME; + + // Number of bytes to read for Volume verification... + unsigned long NumberOfBytesToRead = 0; + + // Starting Offset for 'read' + LONGLONG StartingOffset = 0; + + // Boot Sector information... + PPACKED_BOOT_SECTOR BootSector = NULL; + + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK SuperBlock = NULL; + + // Volume Control Block + PtrExt2VCB PtrVCB = NULL; + + // The File Object for the root directory + PFILE_OBJECT PtrRootFileObject = NULL; + + // Flag + int WeClearedVerifyRequiredBit; + + // Used by a for loop... + unsigned int i; + + // + LARGE_INTEGER VolumeByteOffset; + + unsigned long LogicalBlockSize = 0; + + // Buffer Control Block + PBCB PtrBCB = NULL; + + // Cache Buffer - used for pinned access of volume... + PVOID PtrCacheBuffer = NULL; + + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + + PEXT2_INODE PtrInode = NULL; + + // Inititalising variables + + PtrVPB = IrpSp->Parameters.MountVolume.Vpb; + TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject; + + try + { + // + // 1. Reading in Volume meta data + // + + // Temporarily clear the DO_VERIFY_VOLUME Flag + WeClearedVerifyRequiredBit = 0; + if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) + { + Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ); + WeClearedVerifyRequiredBit = 1; + } + + // Allocating memory for reading in Boot Sector... + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), TargetDeviceObject->SectorSize ); + BootSector = Ext2AllocatePool( PagedPool, NumberOfBytesToRead ); + RtlZeroMemory( BootSector, NumberOfBytesToRead ); + + // Reading in Boot Sector + StartingOffset = 0L; + Ext2PerformVerifyDiskRead ( TargetDeviceObject, + BootSector, StartingOffset, NumberOfBytesToRead ); + + // Allocating memory for reading in Super Block... + + SuperBlock = Ext2AllocatePool( PagedPool, NumberOfBytesToRead ); + RtlZeroMemory( SuperBlock, NumberOfBytesToRead ); + StartingOffset = 1024; + + // Reading in the Super Block... + Ext2PerformVerifyDiskRead ( TargetDeviceObject, + SuperBlock, StartingOffset, NumberOfBytesToRead ); + + // Resetting the DO_VERIFY_VOLUME Flag + if( WeClearedVerifyRequiredBit ) + { + PtrVPB->RealDevice->Flags |= DO_VERIFY_VOLUME; + } + + // Verifying the Super Block.. + if( SuperBlock->s_magic == EXT2_SUPER_MAGIC ) + { + // + // Found a valid super block. + // No more tests for now. + // Assuming that this is an ext2 partition... + // Going ahead with mount. + // + DebugTrace(DEBUG_TRACE_MOUNT, "Valid Ext2 partition detected\nMounting %s...", SuperBlock->s_volume_name); + // + // 2. Creating a volume device object + // + if (!NT_SUCCESS( IoCreateDevice( + Ext2GlobalData.Ext2DriverObject, // (This) Driver object + Ext2QuadAlign( sizeof(Ext2VCB) ), // Device Extension + NULL, // Device Name - no name ;) + FILE_DEVICE_DISK_FILE_SYSTEM, // Disk File System + 0, // DeviceCharacteristics + FALSE, // Not an exclusive device + (PDEVICE_OBJECT *)&PtrVolumeDeviceObject)) // The Volume Device Object + ) + { + try_return( Status ); + } + + // + // Our alignment requirement is the larger of the processor alignment requirement + // already in the volume device object and that in the TargetDeviceObject + // + + if (TargetDeviceObject->AlignmentRequirement > PtrVolumeDeviceObject->AlignmentRequirement) + { + PtrVolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; + } + + // + // Clearing the Device Initialising Flag + // + Ext2ClearFlag( PtrVolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); + + + // + // Setting the Stack Size for the newly created Volume Device Object + // + PtrVolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); + + + // + // 3. Creating the link between Target Device Object + // and the Volume Device Object via the Volume Parameter Block + // + PtrVPB->DeviceObject = PtrVolumeDeviceObject; + + // Remembring the Volume parameters in the VPB bock + for( i = 0; i < 16 ; i++ ) + { + PtrVPB->VolumeLabel[i] = SuperBlock->s_volume_name[i]; + if( SuperBlock->s_volume_name[i] == 0 ) + break; + } + PtrVPB->VolumeLabelLength = i * 2; + PtrVPB->SerialNumber = ((ULONG*)SuperBlock->s_uuid)[0]; + + // + // 4. Initialise the Volume Comtrol Block + // + { + LARGE_INTEGER AllocationSize; + + AllocationSize .QuadPart = + ( EXT2_MIN_BLOCK_SIZE << SuperBlock->s_log_block_size ) * + SuperBlock->s_blocks_count; + + Ext2InitializeVCB( + PtrVolumeDeviceObject, + TargetDeviceObject, + PtrVPB, + &AllocationSize); + PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); + ASSERT( PtrVCB ); + } + + PtrVCB->InodesCount = SuperBlock->s_inodes_count; + PtrVCB->BlocksCount = SuperBlock->s_blocks_count; + PtrVCB->ReservedBlocksCount = SuperBlock->s_r_blocks_count; + PtrVCB->FreeBlocksCount = SuperBlock->s_free_blocks_count; + PtrVCB->FreeInodesCount = SuperBlock->s_free_inodes_count; + PtrVCB->LogBlockSize = SuperBlock->s_log_block_size; + PtrVCB->InodesPerGroup = SuperBlock->s_inodes_per_group; + PtrVCB->BlocksPerGroup = SuperBlock->s_blocks_per_group; + PtrVCB->NoOfGroups = ( SuperBlock->s_blocks_count - SuperBlock->s_first_data_block + + SuperBlock->s_blocks_per_group - 1 ) + / SuperBlock->s_blocks_per_group; + + PtrVCB->PtrGroupDescriptors = Ext2AllocatePool( NonPagedPool, sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups ); + + RtlZeroMemory( PtrVCB->PtrGroupDescriptors , sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups ); + + // + // Attempting to Read in some matadata from the Cache... + // using pin access... + // + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + // + // Reading Group Descriptors... + // + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrBCB, + &PtrCacheBuffer )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); + } + else + { + // + // Saving up Often Used Group Descriptor Information in the VCB... + // + unsigned int DescIndex ; + + DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); + PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer; + for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ ) + { + PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock + = PtrGroupDescriptor[ DescIndex ].bg_inode_table; + + PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock + = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap + ; + PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock + = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap + ; + PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount + = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count; + + PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount + = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count; + } + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + // + // 5. Creating a Root Directory FCB + // + PtrRootFileObject = IoCreateStreamFileObject(NULL, TargetDeviceObject ); + if( !PtrRootFileObject ) + { + try_return( Status ); + } + // + // Associate the file stream with the Volume parameter block... + // I do it now + // + PtrRootFileObject->Vpb = PtrVCB->PtrVPB; + + PtrRootFileObject->ReadAccess = TRUE; + PtrRootFileObject->WriteAccess = TRUE; + + { + PtrExt2ObjectName PtrObjectName; + LARGE_INTEGER ZeroSize; + + PtrObjectName = Ext2AllocateObjectName(); + RtlInitUnicodeString( &PtrObjectName->ObjectName, L"\\" ); + Ext2CopyWideCharToUnicodeString( &PtrObjectName->ObjectName, L"\\" ); + + + ZeroSize.QuadPart = 0; + if ( !NT_SUCCESS( Ext2CreateNewFCB( + &PtrVCB->PtrRootDirectoryFCB, // Root FCB + ZeroSize, // AllocationSize, + ZeroSize, // EndOfFile, + PtrRootFileObject, // The Root Dircetory File Object + PtrVCB, + PtrObjectName ) ) ) + { + try_return( Status ); + } + + + PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY | EXT2_FCB_ROOT_DIRECTORY; + + + } + + PtrVCB->PtrRootDirectoryFCB->DcbFcb.Dcb.PtrDirFileObject = PtrRootFileObject; + PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO; + PtrRootFileObject->SectionObjectPointer = &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject); + RtlInitUnicodeString( &PtrRootFileObject->FileName, L"\\" ); + + Ext2InitializeFCBInodeInfo( PtrVCB->PtrRootDirectoryFCB ); + + // + // Initiating caching for root directory... + // + + CcInitializeCacheMap(PtrRootFileObject, + (PCC_FILE_SIZES)(&(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We will utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrVCB->PtrRootDirectoryFCB ); // The context used in callbacks + + + // + // 6. Update the VCB Flags + // + PtrVCB->VCBFlags |= EXT2_VCB_FLAGS_VOLUME_MOUNTED ; // | EXT2_VCB_FLAGS_VOLUME_READ_ONLY; + + + // + // 7. Mount Success + // + Status = STATUS_SUCCESS; + + { + // + // This block is for testing.... + // To be removed... + + /* + EXT2_INODE Inode ; + Ext2ReadInode( PtrVCB, 100, &Inode ); + DebugTrace( DEBUG_TRACE_MISC, "Inode size= %lX [FS Ctrl]", Inode.i_size ); + Ext2DeallocInode( NULL, PtrVCB, 0xfb6 ); + */ + } + + // ObDereferenceObject( TargetDeviceObject ); + } + else + { + DebugTrace(DEBUG_TRACE_MOUNT, "Failing mount. Partition not Ext2...", 0); + } + + try_exit: NOTHING; + } + finally + { + // Freeing Allocated Memory... + if( SuperBlock != NULL ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", SuperBlock ); + ExFreePool( SuperBlock ); + } + if( BootSector != NULL ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", BootSector); + ExFreePool( BootSector ); + } + + // start unwinding if we were unsuccessful + if (!NT_SUCCESS( Status )) + { + + } + } + + return Status; +} + +/************************************************************************* +* +* Function: Ext2MountVolume() +* +* Description: +* This routine is used for querying the partition information. +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Arguments: +* +* TargetDeviceObject - The target of the query +* PartitionInformation - Receives the result of the query +* +* Return Value: +* +* NTSTATUS - The return status for the operation +* +*************************************************************************/ +NTSTATUS +Ext2GetPartitionInfo ( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PPARTITION_INFORMATION PartitionInformation + ) +{ + PIRP Irp; + KEVENT *PtrEvent = NULL; + NTSTATUS Status; + IO_STATUS_BLOCK Iosb; + + // + // Query the partition table + // + PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) ) ); + + + + + KeInitializeEvent( PtrEvent, NotificationEvent, FALSE ); + + Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO, + TargetDeviceObject, + NULL, + 0, + PartitionInformation, + sizeof(PARTITION_INFORMATION), + FALSE, + PtrEvent, + &Iosb ); + + if ( Irp == NULL ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); + ExFreePool( PtrEvent ); + return 0; + } + + Status = IoCallDriver( TargetDeviceObject, Irp ); + + if ( Status == STATUS_PENDING ) { + + (VOID) KeWaitForSingleObject( PtrEvent, + Executive, + KernelMode, + FALSE, + (PLARGE_INTEGER)NULL ); + + Status = Iosb.Status; + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); + ExFreePool( PtrEvent ); + return Status; +} + +/************************************************************************* +* +* Function: Ext2MountVolume() +* +* Description: +* This routine is used for querying the Drive Layout Information. +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Arguments: +* +* TargetDeviceObject - The target of the query +* PartitionInformation - Receives the result of the query +* +* Return Value: +* +* NTSTATUS - The return status for the operation +* +*************************************************************************/ +NTSTATUS Ext2GetDriveLayout ( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation, + IN int BufferSize + ) +{ + PIRP Irp; + KEVENT *PtrEvent = NULL; + NTSTATUS Status; + IO_STATUS_BLOCK Iosb; + + // + // Query the partition table + // + PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) ) ); + KeInitializeEvent( PtrEvent, NotificationEvent, FALSE ); + Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_LAYOUT, + TargetDeviceObject, + NULL, + 0, + DriveLayoutInformation, + BufferSize, + FALSE, + PtrEvent, + &Iosb ); + + if ( Irp == NULL ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); + ExFreePool( PtrEvent ); + return 0; + } + + Status = IoCallDriver( TargetDeviceObject, Irp ); + + if ( Status == STATUS_PENDING ) { + + (VOID) KeWaitForSingleObject( PtrEvent, + Executive, + KernelMode, + FALSE, + (PLARGE_INTEGER)NULL ); + + Status = Iosb.Status; + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); + ExFreePool( PtrEvent ); + return Status; +} + + +/************************************************************************* +* +* Function: Ext2MountVolume() +* +* Description: +* This routine is used for performing a verify read... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Arguments: +* TargetDeviceObject - The target of the query +* PartitionInformation - Receives the result of the query +* +* Return Value: +* NTSTATUS - The return status for the operation +* +*************************************************************************/ +BOOLEAN Ext2PerformVerifyDiskRead( + IN PDEVICE_OBJECT TargetDeviceObject, + IN PVOID Buffer, + IN LONGLONG Lbo, + IN ULONG NumberOfBytesToRead ) +{ + KEVENT Event; + PIRP Irp; + LARGE_INTEGER ByteOffset; + NTSTATUS Status; + IO_STATUS_BLOCK Iosb; + + // + // Initialize the event we're going to use + // + KeInitializeEvent( &Event, NotificationEvent, FALSE ); + + // + // Build the irp for the operation + // + ByteOffset.QuadPart = Lbo; + Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, + TargetDeviceObject, + Buffer, + NumberOfBytesToRead, + &ByteOffset, + &Event, + &Iosb ); + + if ( Irp == NULL ) + { + Status = FALSE; + } + + Ext2SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME ); + + // + // Call the device to do the read and wait for it to finish. + // + Status = IoCallDriver( TargetDeviceObject, Irp ); + if (Status == STATUS_PENDING) + { + (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + Status = Iosb.Status; + } + + ASSERT(Status != STATUS_VERIFY_REQUIRED); + + // + // Special case this error code because this probably means we used + // the wrong sector size and we want to reject STATUS_WRONG_VOLUME. + // + + if (Status == STATUS_INVALID_PARAMETER) + { + + return FALSE; + } + + // + // If it doesn't succeed then either return or raise the error. + // + + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + // + // And return to our caller + // + return TRUE; +} + +/************************************************************************* +* +* Function: Ext2UserFileSystemRequest() +* +* Description: +* This routine handles User File System Requests +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* +* Arguments: +* +* Irp - Supplies the Irp being processed +* IrpSp - Irp Stack Location pointer +* +* Return Value: NT_STATUS +* +*************************************************************************/ +NTSTATUS Ext2UserFileSystemRequest ( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ) +{ + NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; + ULONG FsControlCode; + + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + try + { +#ifdef _GNU_NTIFS_ + FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.FileSystemControl.FsControlCode; +#else + FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; +#endif + + switch ( FsControlCode ) + { + + case FSCTL_REQUEST_OPLOCK_LEVEL_1: + DebugTrace(DEBUG_TRACE_FSCTRL, "FSCTL_REQUEST_OPLOCK_LEVEL_1", 0); + break; + case FSCTL_REQUEST_OPLOCK_LEVEL_2: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL ", 0); + break; + case FSCTL_REQUEST_BATCH_OPLOCK: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_REQUEST_OPLOCK_LEVEL_2 ", 0); + break; + case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: + DebugTrace(DEBUG_TRACE_MISC, " FSCTL_OPLOCK_BREAK_ACKNOWLEDGE ", 0); + break; + case FSCTL_OPBATCH_ACK_CLOSE_PENDING: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPBATCH_ACK_CLOSE_PENDING ", 0); + break; + case FSCTL_OPLOCK_BREAK_NOTIFY: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPLOCK_BREAK_NOTIFY ", 0); + break; + case FSCTL_OPLOCK_BREAK_ACK_NO_2: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPLOCK_BREAK_ACK_NO_2 ", 0); + break; + case FSCTL_LOCK_VOLUME: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_LOCK_VOLUME ", 0); + break; + case FSCTL_UNLOCK_VOLUME: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_UNLOCK_VOLUME ", 0); + break; + case FSCTL_DISMOUNT_VOLUME: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_DISMOUNT_VOLUME ", 0); + break; + case FSCTL_MARK_VOLUME_DIRTY: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_MARK_VOLUME_DIRTY ", 0); + break; + case FSCTL_IS_VOLUME_DIRTY: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_VOLUME_DIRTY ", 0); + break; + case FSCTL_IS_VOLUME_MOUNTED: + Status = Ext2VerifyVolume(Irp, IrpSp ); + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_VOLUME_MOUNTED ", 0); + break; + case FSCTL_IS_PATHNAME_VALID: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_PATHNAME_VALID ", 0); + break; + case FSCTL_QUERY_RETRIEVAL_POINTERS: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_QUERY_RETRIEVAL_POINTERS ", 0); + break; + case FSCTL_QUERY_FAT_BPB: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_QUERY_FAT_BPB ", 0); + break; + case FSCTL_FILESYSTEM_GET_STATISTICS: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_FILESYSTEM_GET_STATISTICS ", 0); + break; + case FSCTL_GET_VOLUME_BITMAP: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_GET_VOLUME_BITMAP ", 0); + break; + case FSCTL_GET_RETRIEVAL_POINTERS: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_GET_RETRIEVAL_POINTERS ", 0); + break; + case FSCTL_MOVE_FILE: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_MOVE_FILE ", 0); + break; + case FSCTL_ALLOW_EXTENDED_DASD_IO: + DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_ALLOW_EXTENDED_DASD_IO ", 0); + break; + default : + DebugTrace(DEBUG_TRACE_FSCTRL, "Unknown FSCTRL !!!", 0); + + } + + try_exit: NOTHING; + } + finally + { + + } + return Status; +} + + + +NTSTATUS Ext2VerifyVolume ( + IN PIRP Irp, + IN PIO_STACK_LOCATION IrpSp ) +{ + + PVPB PtrVPB; + + PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb; + if( IrpSp->FileObject ) + { + PtrVPB = IrpSp->FileObject->Vpb; + } + if( !PtrVPB ) + { + PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb; + } + + if( !PtrVPB ) + { + return STATUS_WRONG_VOLUME; + } + + + if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) + { + // + // Not doing a verify! + // Just acting as if everyting is fine! + // THis should do for now + // + Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ); + + } + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/filesystems/ext2/src/io.c b/reactos/drivers/filesystems/ext2/src/io.c new file mode 100644 index 00000000000..9991cc1593d --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/io.c @@ -0,0 +1,543 @@ +/************************************************************************* +* +* File: io.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* This file contains low level disk io routines. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_IO + +/************************************************************************* +* +* Function: Ext2PassDownMultiReadWriteIRP() +* +* Description: +* pass down multiple read IRPs as Associated IRPs +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: STATUS_SUCCESS / STATUS_PENDING / Error +* +*************************************************************************/ +NTSTATUS Ext2PassDownMultiReadWriteIRP( + PEXT2_IO_RUN PtrIoRuns, + UINT Count, + ULONG TotalReadWriteLength, + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + BOOLEAN SynchronousIo) +{ + PIRP PtrMasterIrp; + PIRP PtrAssociatedIrp; + PIO_STACK_LOCATION PtrIrpSp; + PMDL PtrMdl; + PtrExt2VCB PtrVCB; + UINT i; + ULONG BufferOffset; + PEXT2_IO_CONTEXT PtrIoContext = NULL; + PKEVENT PtrSyncEvent = NULL; + ULONG LogicalBlockSize; + ULONG ReadWriteLength; + + NTSTATUS RC = STATUS_SUCCESS; + + PtrVCB = PtrFCB->PtrVCB; + PtrMasterIrp = PtrIrpContext->Irp; + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + try + { + if( !SynchronousIo ) + { + IoMarkIrpPending( PtrIrpContext->Irp ); + // We will be returning STATUS_PENDING... + } + + if( !PtrMasterIrp->MdlAddress ) + { + Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength ); + } + + if( SynchronousIo ) + { + PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); + if ( !PtrSyncEvent ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); + } + // + // Allocate and initialize a completion context + // + PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); + if ( !PtrIoContext ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + + RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); + PtrIoContext->Count = Count; + PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; + PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); + PtrIoContext->PtrMasterIrp = PtrMasterIrp; + PtrIoContext->PtrSyncEvent = PtrSyncEvent; + PtrIoContext->ReadWriteLength = TotalReadWriteLength; + + + + for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength ) + { + + ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset; + + // + // Allocating an Associated IRP... + // + PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp, + (CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) ); + PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp; + ASSERT ( PtrAssociatedIrp ); + PtrMasterIrp->AssociatedIrp.IrpCount ++; + + // + // Allocating a Memory Descriptor List... + // + PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, // Virtual Address + ReadWriteLength, FALSE, FALSE, PtrAssociatedIrp ); + + // + // and building a partial MDL... + // + IoBuildPartialMdl( PtrMasterIrp->MdlAddress, + PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength ); + + // + // Create an Irp stack location for ourselves... + // + IoSetNextIrpStackLocation( PtrAssociatedIrp ); + PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp ); + + // + // Setup the Stack location to describe our read. + // + PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; + if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) + { + PtrIrpSp->Parameters.Read.Length = ReadWriteLength; + PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = + PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) + { + PtrIrpSp->Parameters.Write.Length = ReadWriteLength; + PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = + PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + + // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; + // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock; + + + // + // Setup a completion routine... + // + IoSetCompletionRoutine( PtrAssociatedIrp, + SynchronousIo ? + Ext2MultiSyncCompletionRoutine : + Ext2MultiAsyncCompletionRoutine, + PtrIoContext, TRUE, TRUE, TRUE ); + + // + // Initialise the next stack location for the driver below us to use... + // + PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp ); + PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; + if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) + { + PtrIrpSp->Parameters.Read.Length = ReadWriteLength; + PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) + { + PtrIrpSp->Parameters.Write.Length = ReadWriteLength; + PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + + // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; + // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = + // PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); + } + + for( i = 0; i < Count; i++ ) { + DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i); + IoCallDriver( PtrVCB->TargetDeviceObject, PtrIoRuns[ i].PtrAssociatedIrp ); + } + + if( SynchronousIo ) + { + // + // Synchronous IO + // Wait for the IO to complete... + // + DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql()); + KeWaitForSingleObject( PtrSyncEvent, + Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + DbgPrint("DEADLY WAIT DONE\n"); + try_return ( RC ); + } + else + { + // Asynchronous IO... + RC = STATUS_PENDING; + try_return ( RC ); + } + + try_exit: NOTHING; + } + finally + { + if( PtrSyncEvent ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); + ExFreePool( PtrSyncEvent ); + } + if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) + { + // + // This means we are getting out of + // this function without doing a read + // due to an error, maybe... + // + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext); + ExFreePool( PtrIoContext ); + } + } + return(RC); +} + +NTSTATUS Ext2PassDownSingleReadWriteIRP( + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PtrExt2VCB PtrVCB, + LARGE_INTEGER ByteOffset, + uint32 ReadWriteLength, + BOOLEAN SynchronousIo) +{ + NTSTATUS RC = STATUS_SUCCESS; + + PEXT2_IO_CONTEXT PtrIoContext = NULL; + PKEVENT PtrSyncEvent = NULL; + PVOID PtrReadBuffer = NULL; + ULONG ReadBufferLength = 0; + + ULONG LogicalBlockNo = 0; + ULONG LogicalBlockSize = 0; + ULONG PhysicalBlockSize = 0; + + uint32 NumberBytesRead = 0; + int i; + PIO_STACK_LOCATION PtrIrpNextSp = NULL; + + try + { + if( !PtrIrp->MdlAddress ) + { + Ext2LockCallersBuffer( PtrIrp, TRUE, ReadWriteLength ); + } + + + if( SynchronousIo ) + { + PtrSyncEvent = Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); + if ( !PtrSyncEvent ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); + } + + // + // Allocate and initialize a completion context + // + PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); + if ( !PtrIoContext ) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + + RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); + PtrIoContext->Count = 1; + PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; + PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); + PtrIoContext->PtrMasterIrp = NULL; + PtrIoContext->PtrSyncEvent = PtrSyncEvent; + PtrIoContext->ReadWriteLength = ReadWriteLength; + + IoSetCompletionRoutine( PtrIrp, + SynchronousIo ? + Ext2SingleSyncCompletionRoutine: + Ext2SingleAsyncCompletionRoutine, + PtrIoContext, TRUE, TRUE, TRUE ); + + // + // Setup the next IRP stack location in the associated Irp for the disk + // driver beneath us. + // + PtrIrpNextSp = IoGetNextIrpStackLocation( PtrIrp ); + + // + // Setup the Stack location to do a read from the disk driver. + // + PtrIrpNextSp->MajorFunction = PtrIrpContext->MajorFunction; + if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) + { + PtrIrpNextSp->Parameters.Read.Length = ReadWriteLength; + PtrIrpNextSp->Parameters.Read.ByteOffset = ByteOffset; + } + else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) + { + PtrIrpNextSp->Parameters.Write.Length = ReadWriteLength; + PtrIrpNextSp->Parameters.Write.ByteOffset = ByteOffset; + } + // + // Issue the read / write request + // + RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); + + if( SynchronousIo ) + { + // + // Wait for completion... + // + RC = KeWaitForSingleObject( &PtrIoContext->PtrSyncEvent, + Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); + + RC = STATUS_SUCCESS; + } + else + { + RC = STATUS_PENDING; + } + + try_exit: NOTHING; + } + finally + { + if( PtrSyncEvent ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); + ExFreePool( PtrSyncEvent ); + } + if( PtrIoContext && !( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) + { + // + // This means we are getting out of + // this function without doing a read / write + // due to an error, maybe... + // + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext ); + ExFreePool( PtrIoContext ); + } + } + return RC; +} + + +/************************************************************************* +* +* Function: Ext2SingleSyncCompletionRoutine() +* +* Description: +* Synchronous I/O Completion Routine +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2SingleSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + PEXT2_IO_CONTEXT PtrContext = Contxt; + + if( Irp->PendingReturned ) + IoMarkIrpPending( Irp ); + + ASSERT( PtrContext ); + ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT ); + + KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE ); + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); + ExFreePool( PtrContext ); + + return STATUS_SUCCESS; +} + +/************************************************************************* +* +* Function: Ext2SingleAsyncCompletionRoutine() +* +* Description: +* Asynchronous I/O Completion Routine +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2SingleAsyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + PEXT2_IO_CONTEXT PtrContext = Contxt; + + if( Irp->PendingReturned ) + IoMarkIrpPending( Irp ); + + ASSERT( PtrContext ); + ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT ); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); + ExFreePool( PtrContext ); + + return STATUS_SUCCESS; +} + +/************************************************************************* +* +* Function: Ext2MultiSyncCompletionRoutine() +* +* Description: +* Synchronous I/O Completion Routine +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2MultiSyncCompletionRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + + PEXT2_IO_CONTEXT PtrContext = Contxt; + ASSERT( PtrContext ); + + if( Irp->PendingReturned ) + { + IoMarkIrpPending( Irp ); + } + + if (!NT_SUCCESS( Irp->IoStatus.Status )) + { + PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status; + } + + if (InterlockedDecrement( &PtrContext->Count ) == 0) + { + if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) ) + { + PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength; + } + else + { + PtrContext->PtrMasterIrp->IoStatus.Information = 0; + } + + KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE ); + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); + ExFreePool( PtrContext ); + } + + // + // The master Irp will be automatically completed + // when all the associated IRPs are completed + // + return STATUS_SUCCESS; +} + +/************************************************************************* +* +* Function: Ext2MultiAsyncCompletionRoutine() +* +* Description: +* Asynchronous I/O Completion Routine +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2MultiAsyncCompletionRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + + PEXT2_IO_CONTEXT PtrContext = Contxt; + ASSERT( PtrContext ); + + if( Irp->PendingReturned ) + { + IoMarkIrpPending( Irp ); + } + + if (!NT_SUCCESS( Irp->IoStatus.Status )) + { + PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status; + } + + if (InterlockedDecrement( &PtrContext->Count ) == 0) + { + if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) ) + { + PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength; + } + else + { + PtrContext->PtrMasterIrp->IoStatus.Information = 0; + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); + ExFreePool( PtrContext ); + } + + // + // The master Irp will be automatically completed + // when all the associated IRPs are completed + // Returning STATUS_SUCCESS to continue postprocessing... + // + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/filesystems/ext2/src/metadata.c b/reactos/drivers/filesystems/ext2/src/metadata.c new file mode 100644 index 00000000000..1369b58fc2c --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/metadata.c @@ -0,0 +1,2837 @@ +/************************************************************************* +* +* File: metadata.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Should contain code to handle Ext2 Metadata. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +#define EXT2_BUG_CHECK_ID EXT2_FILE_METADATA_IO + +#define DEBUG_LEVEL ( DEBUG_TRACE_METADATA ) + +extern Ext2Data Ext2GlobalData; + +/************************************************************************* +* +* Function: Ext2ReadInode() +* +* Description: +* +* The functions will read in the specifiec inode and return it in a buffer +* +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* +* Arguements: +* +* +* +* Return Value: The Status of the Read IO +* +*************************************************************************/ + +NTSTATUS Ext2ReadInode ( + PtrExt2VCB PtrVcb, // the Volume Control Block + uint32 InodeNo, // The Inode no + PEXT2_INODE PtrInode // The Inode Buffer + ) +{ + // The Status to be returned... + NTSTATUS RC = STATUS_SUCCESS; + + // The Read Buffer Pointer + BYTE * PtrPinnedReadBuffer = NULL; + + PEXT2_INODE PtrTempInode; + + // Buffer Control Block + PBCB PtrBCB = NULL; + + LARGE_INTEGER VolumeByteOffset, TempOffset; + + ULONG LogicalBlockSize = 0; + + ULONG NumberOfBytesToRead = 0; + ULONG Difference = 0; + + ULONG GroupNo; + int Index; + + try + { + ASSERT(PtrVcb); + ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + // Inode numbers start at 1 and not from 0 + // Hence 1 is subtracted from InodeNo to get a zero based index... + GroupNo = ( InodeNo - 1 ) / PtrVcb->InodesPerGroup; + + if( GroupNo >= PtrVcb->NoOfGroups ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo ); + DebugTrace(DEBUG_TRACE_MISC, "Only %d groups available on disk", PtrVcb->NoOfGroups ); + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + + //if( PtrVcb->InodeTableBlock[ GroupNo ] == 0 ) + if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo ); + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + + // Inode numbers start at 1 and not from 0 + // Hence 1 is subtracted from InodeNo to get a zero based index... + Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup ); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize; + NumberOfBytesToRead = sizeof(EXT2_INODE); // LogicalBlockSize; + + VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock + * LogicalBlockSize + Index * sizeof(EXT2_INODE); + //VolumeByteOffset.QuadPart = PtrVcb->InodeTableBlock[ GroupNo ] * LogicalBlockSize + + // Index * sizeof(EXT2_INODE); + + TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize ); + if( TempOffset.QuadPart != VolumeByteOffset.QuadPart ) + { + // TempOffset.QuadPart -= LogicalBlockSize; + Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize ); + VolumeByteOffset.QuadPart -= Difference; + NumberOfBytesToRead += Difference; + } + + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if( NumberOfBytesToRead > LogicalBlockSize ) + { + // Multiple blocks being read in... + // Can cause overlap + // Watch out!!!! + Ext2BreakPoint(); + } + + + + if (!CcMapData( PtrVcb->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedReadBuffer )) + { + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + else + { + PtrTempInode = (PEXT2_INODE) ( PtrPinnedReadBuffer + Difference ); + RtlCopyMemory( PtrInode, PtrTempInode , sizeof(EXT2_INODE) ); + } + + try_exit: NOTHING; + } + finally + { + if( PtrBCB ) + { + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + } + return RC; +} + +/************************************************************************* +* +* Function: Ext2InitializeFCBInodeInfo() +* +* Description: +* The functions will initialize the FCB with its i-node info +* provided it hasn't been initialized as yet... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Arguements: +* Pointer to FCB +* +* Return Value: None +* +*************************************************************************/ +void Ext2InitializeFCBInodeInfo ( + PtrExt2FCB PtrFCB ) +{ + PtrExt2VCB PtrVCB = NULL; + EXT2_INODE Inode; + int i; + ULONG LogicalBlockSize; + + PtrVCB = PtrFCB->PtrVCB; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + if( !Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "Reading in the i-node no %d", PtrFCB->INodeNo ); + + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + + for( i = 0; i < EXT2_N_BLOCKS ; i++ ) + { + PtrFCB->IBlock[i] = Inode.i_block[ i ]; + } + + PtrFCB->CreationTime.QuadPart = ( __int64 )Inode.i_ctime * 10000000; + PtrFCB->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; + PtrFCB->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_atime * 10000000); + PtrFCB->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_mtime * 10000000); + + + PtrFCB->LinkCount = Inode.i_links_count; + + // Getting the file type... + if( ! Ext2IsModeRegularFile( Inode.i_mode ) ) + { + // Not a reqular file... + if( Ext2IsModeDirectory( Inode.i_mode) ) + { + // Directory... + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ); + } + else + { + // Special File... + // Treated with respect... ;) + // + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ); + } + + } + if( Ext2IsModeHidden( Inode.i_mode ) ) + { + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ); + } + if( Ext2IsModeReadOnly( Inode.i_mode ) ) + { + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ); + } + + + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = Inode.i_size; + Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart = Inode.i_blocks * 512; + + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) + { + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart -= LogicalBlockSize / 512; + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [metadata]", Inode ); + } +} + +/************************************************************************* +* +* Function: Ext2AllocInode() +* +* Description: +* The functions will allocate a new on-disk i-node +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Arguements: +* Parent Inode no +* +* Return Value: The new i-node no or zero +* +*************************************************************************/ +ULONG Ext2AllocInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG ParentINodeNo ) +{ + ULONG InodeNo = 0; + + // Buffer Control Block + PBCB PtrBitmapBCB = NULL; + BYTE * PtrBitmapBuffer = NULL; + + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + ULONG NumberOfBytesToRead = 0; + + if( PtrVCB->FreeInodesCount == 0) + { + // + // No Free Inodes left... + // Fail request... + // + return 0; + } + + try + { + // unsigned int DescIndex ; + BOOLEAN Found = FALSE; + ULONG Block; + ULONG GroupNo; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ ) + { + if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount ) + break; + } + + VolumeByteOffset.QuadPart = + PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock * LogicalBlockSize; + + NumberOfBytesToRead = PtrVCB->InodesCount / PtrVCB->NoOfGroups; + + if( NumberOfBytesToRead % 8 ) + { + NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1; + } + else + { + NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ; + } + + for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); + Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize) + { + // + // Read in the bitmap block... + // + ULONG i, j; + BYTE Bitmap; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, //NumberOfBytesToRead, + TRUE, + &PtrBitmapBCB, + (PVOID*)&PtrBitmapBuffer ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + return 0; + } + + // + // Is there a free inode... + // + for( i = 0; !Found && i < LogicalBlockSize && + i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ ) + { + Bitmap = PtrBitmapBuffer[i]; + if( Bitmap != 0xff ) + { + // + // Found a free inode... + for( j = 0; !Found && j < 8; j++ ) + { + if( ( Bitmap & 0x01 ) == 0 ) + { + // + // Found... + Found = TRUE; + + // Inode numbers start at 1 and not from 0 + // Hence 1 is addded to j + InodeNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 + + ( GroupNo * PtrVCB->InodesPerGroup ); + + // Update the inode on the disk... + Bitmap = 1 << j; + PtrBitmapBuffer[i] |= Bitmap; + + CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); + + // + // Should update the bitmaps in the other groups too... + // + break; + } + Bitmap = Bitmap >> 1; + } + } + } + // + // Unpin the BCB... + // + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + } + + { + // + // Updating the Inode count in the Group Descriptor... + // + PBCB PtrDescriptorBCB = NULL; + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount--; + + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrDescriptorBCB , + (PVOID*)&PtrGroupDescriptor )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + // + // Ignore this error... + // Not fatal... + } + else + { + PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; + // + // Not synchronously flushing this information... + // Lazy writing will do... + // + CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); + CcUnpinData( PtrDescriptorBCB ); + PtrDescriptorBCB = NULL; + } + } + + + // + // Update the Inode count... + // in the Super Block... + // + { + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + + PtrVCB->FreeInodesCount--; + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + + // THis shouldn't be more than a block in size... + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + } + else + { + PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount; + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + if( PtrSuperBlockBCB ) + { + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + + } + } + + try_exit: NOTHING; + } + finally + { + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + } + DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating an inode - I-Node no : %ld", InodeNo ); + + return InodeNo; + +} + +/************************************************************************* +* +* Function: Ext2DeallocInode() +* +* Description: +* The functions will deallocate an i-node +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2DeallocInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG INodeNo ) +{ + BOOLEAN RC = TRUE; + + // Buffer Control Block + PBCB PtrBitmapBCB = NULL; + BYTE * PtrBitmapBuffer = NULL; + + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + + DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating an inode - I-Node no : %ld", INodeNo ); + + try + { + ULONG BlockIndex ; + ULONG BitmapIndex; + ULONG GroupNo; + BYTE Bitmap; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + GroupNo = INodeNo / PtrVCB->InodesPerGroup; + INodeNo = INodeNo % PtrVCB->InodesPerGroup; + + BitmapIndex = (INodeNo-1) / 8; + Bitmap = 1 << ( (INodeNo-1) % 8 ); + BlockIndex = BitmapIndex / LogicalBlockSize; + // Adjusting to index into the Logical block that contains the bitmap + BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize ); + + VolumeByteOffset.QuadPart = + ( PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock + BlockIndex ) + * LogicalBlockSize; + + // + // Read in the bitmap block... + // + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, // Just the block that contains the bitmap will do... + TRUE, // Can Wait... + &PtrBitmapBCB, + (PVOID*)&PtrBitmapBuffer ) ) + { + // Unable to Pin the data into the cache... + try_return (RC = FALSE); + } + + // + // Locate the inode... + // This inode is in the byte PtrBitmapBuffer[ BitmapIndex ] + if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0) + { + // This shouldn't have been so... + // The inode was never allocated! + // How to deallocate something that hasn't been allocated? + // Hmmm... ;) + // Ignore this error... + try_return (RC = TRUE); + } + + + // Setting the bit for the inode... + PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap); + + // Update the cache... + CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); + + // Save up the BCB for forcing a synchronous write... + // Before completing the IRP... + Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); + + + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + + { + // + // Updating the Inode count in the Group Descriptor... + // + PBCB PtrDescriptorBCB = NULL; + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + ULONG NumberOfBytesToRead = 0; + + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount++; + + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrDescriptorBCB , + (PVOID*)&PtrGroupDescriptor )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + // + // Ignore this error... + // Not fatal... + } + else + { + PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; + // + // Not synchronously flushing this information... + // Lazy writing will do... + // + CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); + CcUnpinData( PtrDescriptorBCB ); + PtrDescriptorBCB = NULL; + } + } + + + // + // Update the Inode count... + // in the Super Block + // and in the VCB + // + { + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + ULONG NumberOfBytesToRead = 0; + + PtrVCB->FreeInodesCount++; + + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + } + else + { + PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount; + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + if( PtrSuperBlockBCB ) + { + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + + } + } + try_exit: NOTHING; + } + finally + { + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + } + return RC; +} + +/************************************************************************* +* +* Function: Ext2WriteInode() +* +* Description: +* The functions will write an i-node to disk +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Return Value: Success / Failure... +* +*************************************************************************/ +NTSTATUS Ext2WriteInode( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVcb, // the Volume Control Block + uint32 InodeNo, // The Inode no + PEXT2_INODE PtrInode // The Inode Buffer + ) +{ + // The Status to be returned... + NTSTATUS RC = STATUS_SUCCESS; + + // The Read Buffer Pointer + BYTE * PtrPinnedBuffer = NULL; + + PEXT2_INODE PtrTempInode; + + // Buffer Control Block + PBCB PtrBCB = NULL; + + LARGE_INTEGER VolumeByteOffset, TempOffset; + + ULONG LogicalBlockSize = 0; + ULONG NumberOfBytesToRead = 0; + ULONG Difference = 0; + ULONG GroupNo; + int Index; + + try + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Writing and updating an inode - I-Node no : %ld", InodeNo ); + + ASSERT(PtrVcb); + ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + GroupNo = InodeNo / PtrVcb->InodesPerGroup; + + if( GroupNo >= PtrVcb->NoOfGroups ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo ); + DebugTrace(DEBUG_TRACE_MISC, "Only %d groups available on disk", PtrVcb->NoOfGroups ); + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + + if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 ) + { + DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo ); + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + + Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup ); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize; + NumberOfBytesToRead = sizeof(EXT2_INODE); + + VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock + * LogicalBlockSize + Index * sizeof(EXT2_INODE); + + TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize ); + if( TempOffset.QuadPart != VolumeByteOffset.QuadPart ) + { + // TempOffset.QuadPart -= LogicalBlockSize; + Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize ); + VolumeByteOffset.QuadPart -= Difference; + NumberOfBytesToRead += Difference; + } + + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if( NumberOfBytesToRead > LogicalBlockSize ) + { + // Multiple blocks being read in... + // Can cause overlap + // Watch out!!!! + Ext2BreakPoint(); + } + + if( !CcPinRead( PtrVcb->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, // Can Wait... + &PtrBCB, + (PVOID*)&PtrPinnedBuffer ) ) + { + RC = STATUS_UNSUCCESSFUL; + try_return( RC ); + } + else + { + RtlCopyMemory( PtrPinnedBuffer + Difference, PtrInode, sizeof(EXT2_INODE) ); + CcSetDirtyPinnedData( PtrBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrBCB, PtrVcb->PtrStreamFileObject ); + } + + try_exit: NOTHING; + } + finally + { + if( PtrBCB ) + { + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + } + return RC; +} + + +/************************************************************************* +* +* Function: Ext2MakeNewDirectoryEntry() +* +* Description: +* The functions will make a new directory entry in a directory file... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2MakeNewDirectoryEntry( + PtrExt2IrpContext PtrIrpContext, // The Irp context + PtrExt2FCB PtrParentFCB, // Parent Folder FCB + PFILE_OBJECT PtrFileObject, // Parent Folder Object + PUNICODE_STRING PtrName, // New entry's name + ULONG Type, // The type of the new entry + ULONG NewInodeNo) // The inode no of the new entry... +{ + PBCB PtrLastBlockBCB = NULL; + BYTE * PtrLastBlock = NULL; + EXT2_DIR_ENTRY DirEntry; + PEXT2_DIR_ENTRY PtrTempDirEntry; + + ULONG BlockNo = 0; + ULONG i; + PtrExt2VCB PtrVCB; + LARGE_INTEGER VolumeByteOffset; + unsigned long LogicalBlockSize = 0; + unsigned long NumberOfBytesToRead = 0; + BOOLEAN RC = FALSE; + + USHORT HeaderLength = sizeof( EXT2_DIR_ENTRY ); + USHORT NewEntryLength = 0; + USHORT MinLength = 0; + #define ActualLength (PtrTempDirEntry->rec_len) + #define NameLength (PtrTempDirEntry->name_len) + + try + { + ASSERT( PtrFileObject ); + + DebugTrace( DEBUG_TRACE_SPECIAL, "Making directory entry: %S", PtrName->Buffer ); + + PtrVCB = PtrParentFCB->PtrVCB; + AssertVCB( PtrVCB); + + HeaderLength = sizeof( EXT2_DIR_ENTRY ) - + (sizeof( char ) * EXT2_NAME_LEN); + // 1. Setting up the entry... + NewEntryLength = sizeof( EXT2_DIR_ENTRY ) - ( sizeof( char ) * ( EXT2_NAME_LEN - (PtrName->Length / 2) ) ); + // Length should be a multiplicant of 4 + NewEntryLength = ((NewEntryLength + 3 ) & 0xfffffffc); + + RtlZeroMemory( &DirEntry, sizeof( EXT2_DIR_ENTRY ) ); + + DirEntry.file_type = (BYTE) Type; + DirEntry.inode = NewInodeNo; + DirEntry.name_len = (BYTE)(PtrName->Length / 2 ); // Does not include a NULL + + // DirEntry.rec_len = (USHORT) NewEntryLength; + + for( i = 0; ; i++ ) + { + if( i < (ULONG)( PtrName->Length / 2 ) ) + { + DirEntry.name[i] = (CHAR) PtrName->Buffer[i]; + } + else + { + //DirEntry.name[i] = 0; // Entry need not be zero terminated... + break; + } + } + + // + // 2. Read the block in the directory... + // Initiate Caching... + if ( PtrFileObject->PrivateCacheMap == NULL ) + { + CcInitializeCacheMap( + PtrFileObject, + (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrParentFCB ); // The context used in callbacks + } + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + if( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart > 0 ) + { + BlockNo = (ULONG) ( (PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) / LogicalBlockSize) ; + } + else + { + // This directory doesn't have any data blocks... + // Allocate a new block... + if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) ) + { + try_return( RC = FALSE ); + } + else + { + // Bring in the newly allocated block to the cache... + VolumeByteOffset.QuadPart = 0; + + if( !CcPreparePinWrite( + PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrLastBlockBCB, + (PVOID*)&PtrLastBlock ) ) + { + try_return( RC = FALSE ); + } + + DirEntry.rec_len = (USHORT)LogicalBlockSize; + RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); + CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); + try_return( RC = TRUE ); + } + } + + VolumeByteOffset.QuadPart = BlockNo * LogicalBlockSize; + CcMapData( PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrLastBlockBCB, + (PVOID*)&PtrLastBlock ); + + for( i = 0 ; i < LogicalBlockSize; ) + { + PtrTempDirEntry = (PEXT2_DIR_ENTRY) &PtrLastBlock[ i ]; + + MinLength = HeaderLength + NameLength; + MinLength = ( HeaderLength + NameLength + 3 ) & 0xfffffffc; + + + if( PtrTempDirEntry->rec_len == 0 ) + { + if( i == 0 ) + { + // Must be an empty Block... + // Insert here... + // ---------------->>> + + CcPinMappedData( PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrLastBlockBCB ); + + DirEntry.rec_len = (USHORT)LogicalBlockSize; + + RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); + CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); + try_return( RC = TRUE ); + } + else + { + // This shouldn't be so... + // Something is wrong... + // Fail this request... + try_return( RC = FALSE ); + } + } + if( ActualLength - MinLength >= NewEntryLength ) + { + // Insert here... + // ----------------> + + // Getting ready for updation... + CcPinMappedData( PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrLastBlockBCB ); + + + DirEntry.rec_len = ActualLength - MinLength; + + // Updating the current last entry + PtrTempDirEntry->rec_len = MinLength; + i += PtrTempDirEntry->rec_len; + + // Making the new entry... + RtlCopyBytes( (PtrLastBlock + i) , &DirEntry, NewEntryLength); + CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); + try_return( RC = TRUE ); + + } + i += PtrTempDirEntry->rec_len; + } + + // Will have to allocate a new block... + // Old block does not have enough space.. + if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) ) + { + try_return( RC = FALSE ); + } + else + { + // unpin the previously pinned block + CcUnpinData( PtrLastBlockBCB ); + PtrLastBlockBCB = NULL; + + // Bring in the newly allocated block to the cache... + VolumeByteOffset.QuadPart += LogicalBlockSize; + if( !CcPreparePinWrite( + PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrLastBlockBCB, + (PVOID*)&PtrLastBlock ) ) + { + try_return( RC = FALSE ); + } + + DirEntry.rec_len = (USHORT)LogicalBlockSize; + RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); + CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); + try_return( RC = TRUE ); + } + try_exit: NOTHING; + } + finally + { + if( PtrLastBlockBCB ) + { + CcUnpinData( PtrLastBlockBCB ); + PtrLastBlockBCB = NULL; + } + } + if( RC == FALSE ) + { + DebugTrace( DEBUG_TRACE_ERROR, "Failed to making directory entry: %S", PtrName->Buffer ); + } + return RC; +} + + +BOOLEAN Ext2FreeDirectoryEntry( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrParentFCB, + PUNICODE_STRING PtrName) +{ + + PBCB PtrDataBlockBCB = NULL; + BYTE * PtrDataBlock = NULL; + PFILE_OBJECT PtrFileObject = NULL; + PEXT2_DIR_ENTRY PtrTempDirEntry; + LONGLONG ByteOffset = 0; + PtrExt2VCB PtrVCB; + LARGE_INTEGER VolumeByteOffset; + unsigned long LogicalBlockSize = 0; + BOOLEAN RC = FALSE; + + + try + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Freeing directory entry: %S", PtrName->Buffer ); + + PtrVCB = PtrParentFCB->PtrVCB; + AssertVCB( PtrVCB); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; + if( PtrFileObject == NULL ) + { + return FALSE; + } + + + // + // 1. Read the block in the directory... + // Initiate Caching... + if ( PtrFileObject->PrivateCacheMap == NULL ) + { + CcInitializeCacheMap( + PtrFileObject, + (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrParentFCB ); // The context used in callbacks + } + + for( ByteOffset = 0; + ByteOffset < PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart; + ByteOffset += LogicalBlockSize ) + { + ULONG Index = 0; + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + + + VolumeByteOffset.QuadPart = ByteOffset; + + CcPinRead( PtrFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrDataBlockBCB, + (PVOID*)&PtrDataBlock ); + while( Index < LogicalBlockSize ) + { + ULONG i; + // Parse... + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrDataBlock[ Index ]; + Index += PtrDirEntry->rec_len; + + if( PtrDirEntry->inode == 0 ) + { + // This is a deleted entry... + continue; + } + if( ( PtrName->Length/2 ) != PtrDirEntry->name_len ) + continue; + for( i = 0; ; i++ ) + { + if( PtrDirEntry->name_len == i ) + { + // Remove the entry by setting the inode no to zero + PtrDirEntry->inode = 0; + + // Update the disk + CcSetDirtyPinnedData( PtrDataBlockBCB , NULL ); + Ext2SaveBCB( PtrIrpContext, PtrDataBlockBCB, PtrFileObject ); + CcUnpinData( PtrDataBlockBCB ); + PtrDataBlockBCB = NULL; + + // Return to caller... + try_return( RC = TRUE ); + } + if( PtrName->Buffer[i] != PtrDirEntry->name[i] ) + { + break; + } + } + } + CcUnpinData( PtrDataBlockBCB ); + PtrDataBlockBCB = NULL; + } + try_return( RC = FALSE ); + + try_exit: NOTHING; + } + finally + { + if( PtrDataBlockBCB ) + { + CcUnpinData( PtrDataBlockBCB ); + PtrDataBlockBCB = NULL; + } + } + return RC; +} + +/************************************************************************* +* +* Function: Ext2AddBlockToFile() +* +* Description: +* The functions will add a block to a file... +* It will update the allocation size but not the file size... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2AddBlockToFile( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + BOOLEAN UpdateFileSize) +{ + BOOLEAN RC = TRUE; + + ULONG NewBlockNo = 0; + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + ULONG NoOfBlocks = 0; + EXT2_INODE Inode; + + ULONG DirectBlocks = 0; + ULONG SingleIndirectBlocks = 0; + ULONG DoubleIndirectBlocks = 0; + ULONG TripleIndirectBlocks = 0; + + ULONG *PtrSIBBuffer = NULL; + PBCB PtrSIBBCB = NULL; + ULONG *PtrDIBBuffer = NULL; + PBCB PtrDIBBCB = NULL; + + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + DirectBlocks = EXT2_NDIR_BLOCKS ; + SingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG ); + DoubleIndirectBlocks = SingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + TripleIndirectBlocks = DoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + + try + { + if( PtrFCB && PtrFCB->FCBName->ObjectName.Length ) + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Adding Blocks to file %S", PtrFCB->FCBName->ObjectName.Buffer ); + } + + Ext2InitializeFCBInodeInfo( PtrFCB ); + + // Allocate a block... + NewBlockNo = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + + if( NewBlockNo == 0 ) + { + try_return (RC = FALSE ); + } + + // No of blocks CURRENTLY allocated... + NoOfBlocks = (ULONG) PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart / LogicalBlockSize; + + + if( NoOfBlocks < EXT2_NDIR_BLOCKS ) + { + // + // A direct data block will do... + // + + PtrFCB->IBlock[ NoOfBlocks ] = NewBlockNo; + + // Update the inode... + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + Inode.i_block[ NoOfBlocks ] = NewBlockNo; + Inode.i_blocks += ( LogicalBlockSize / 512 ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; + if( UpdateFileSize ) + { + Inode.i_size += LogicalBlockSize; + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; + } + + + if( PtrFileObject->PrivateCacheMap != NULL) + { + // + // Caching has been initiated... + // Let the Cache manager in on these changes... + // + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + + + // Updating the inode... + if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + try_return (RC = TRUE); + } + else + { + try_return (RC = FALSE ); + } + + } + else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks) ) + { + // + // A single indirect data block will do... + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 ) + { + // A Single Indirect block should be allocated as well!! + PtrFCB->IBlock[ EXT2_IND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 ) + { + try_return (RC = FALSE ); + } + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + // Bring in the new block to the cache + // Zero it out + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + // Just bring in the SIB to the cache + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + + // Update the inode... + + Inode.i_block[ EXT2_IND_BLOCK ] = PtrFCB->IBlock[ EXT2_IND_BLOCK ]; + Inode.i_blocks += ( LogicalBlockSize / 512 ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; + if( UpdateFileSize ) + { + Inode.i_size += LogicalBlockSize; + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; + } + if( PtrFileObject->PrivateCacheMap != NULL) + { + // + // Caching has been initiated... + // Let the Cache manager in on these changes... + // + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + + if( !NT_SUCCESS( Ext2WriteInode( + PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + try_return (RC = FALSE ); + } + + + // Update the SIB... + PtrSIBBuffer[ NoOfBlocks - DirectBlocks ] = NewBlockNo; + CcSetDirtyPinnedData( PtrSIBBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); + + try_return (RC = TRUE); + + } + else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks + DoubleIndirectBlocks ) ) + { + // + // A double indirect block will do... + // + ULONG SBlockNo; + ULONG BlockNo; + + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) + { + // A double indirect pointer block should be allocated as well!! + PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) + { + try_return (RC = FALSE ); + } + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + // Bring in the new block to the cache + // Zero it out + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrDIBBCB, + (PVOID*)&PtrDIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + // Just bring in the DIB to the cache + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrDIBBCB, + (PVOID*)&PtrDIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + + // See if a single indirect 'pointer' block + // should also be allocated... + BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks ); + SBlockNo = BlockNo / SingleIndirectBlocks; + if( BlockNo % SingleIndirectBlocks ) + { + // A single indirect 'pointer' block + // should also be allocated... + PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + CcSetDirtyPinnedData( PtrDIBBCB, NULL ); + VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; + + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + BlockNo = BlockNo % SingleIndirectBlocks; + + // Update the inode... + + Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ]; + Inode.i_blocks += ( LogicalBlockSize / 512 ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; + if( UpdateFileSize ) + { + Inode.i_size += LogicalBlockSize; + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; + } + if( PtrFileObject->PrivateCacheMap != NULL) + { + // + // Caching has been initiated... + // Let the Cache manager in on these changes... + // + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + + if( !NT_SUCCESS( Ext2WriteInode( + PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + try_return (RC = FALSE ); + } + + + // Update the SIB... + PtrSIBBuffer[ BlockNo ] = NewBlockNo; + CcSetDirtyPinnedData( PtrSIBBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); + Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject ); + + try_return (RC = TRUE); + + } + else + { + // + // A Triple Indirect block is required + // + ULONG SBlockNo; + ULONG BlockNo; + + // This is not supported as yet... + try_return (RC = FALSE); + + Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); + + if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] == 0 ) + { + // A double indirect pointer block should be allocated as well!! + PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) + { + try_return (RC = FALSE ); + } + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + // Bring in the new block to the cache + // Zero it out + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrDIBBCB, + (PVOID*)&PtrDIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + // Just bring in the DIB to the cache + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrDIBBCB, + (PVOID*)&PtrDIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + + // See if a single indirect 'pointer' block + // should also be allocated... + BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks ); + SBlockNo = BlockNo / SingleIndirectBlocks; + if( BlockNo % SingleIndirectBlocks ) + { + // A single indirect 'pointer' block + // should also be allocated... + PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); + CcSetDirtyPinnedData( PtrDIBBCB, NULL ); + VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; + + Inode.i_blocks += ( LogicalBlockSize / 512 ); + + if( !CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Zero out the block... + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + else + { + VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrSIBBCB, + (PVOID*)&PtrSIBBuffer ) ) + { + try_return( RC = FALSE ); + } + } + BlockNo = BlockNo % SingleIndirectBlocks; + + // Update the inode... + + Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ]; + Inode.i_blocks += ( LogicalBlockSize / 512 ); + PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; + if( UpdateFileSize ) + { + Inode.i_size += LogicalBlockSize; + PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; + } + if( PtrFileObject->PrivateCacheMap != NULL) + { + // + // Caching has been initiated... + // Let the Cache manager in on these changes... + // + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + + if( !NT_SUCCESS( Ext2WriteInode( + PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + try_return (RC = FALSE ); + } + + + // Update the SIB... + PtrSIBBuffer[ BlockNo ] = NewBlockNo; + CcSetDirtyPinnedData( PtrSIBBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); + Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject ); + + try_return (RC = TRUE); + + } + + try_exit: NOTHING; + } + finally + { + if( PtrSIBBCB ) + { + CcUnpinData( PtrSIBBCB ); + PtrSIBBCB = NULL; + } + if( PtrDIBBCB ) + { + CcUnpinData( PtrDIBBCB ); + PtrDIBBCB = NULL; + } + } + return RC; +} + +/************************************************************************* +* +* Function: Ext2AllocBlock() +* +* Description: +* The functions will allocate a new block +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* +* Return Value: Success / Failure... +* +*************************************************************************/ +ULONG Ext2AllocBlock( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG Count) +{ + // Buffer Control Block + PBCB PtrBitmapBCB = NULL; + BYTE * PtrBitmapBuffer = NULL; + ULONG BlockNo = 0; + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + ULONG NumberOfBytesToRead = 0; + + if( PtrVCB->FreeBlocksCount == 0 ) + { + // + // No Free Block left... + // Fail request... + // + return 0; + } + + try + { + BOOLEAN Found = FALSE; + ULONG Block; + ULONG GroupNo; + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ ) + { + if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount ) + break; + } + + VolumeByteOffset.QuadPart = + PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock * LogicalBlockSize; + + NumberOfBytesToRead = PtrVCB->BlocksCount / PtrVCB->NoOfGroups; + + if( NumberOfBytesToRead % 8 ) + { + NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1; + } + else + { + NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ; + } + + + for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); + Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize) + { + // + // Read in the block bitmap block... + ULONG i, j; + BYTE Bitmap; + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, // NumberOfBytesToRead, + TRUE, + &PtrBitmapBCB, + (PVOID*)&PtrBitmapBuffer ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + try_return( BlockNo = 0 ); + } + + // + // Is there a free block... + // + for( i = 0; !Found && i < LogicalBlockSize && + i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ ) + { + Bitmap = PtrBitmapBuffer[i]; + if( Bitmap != 0xff ) + { + // + // Found a free block... + for( j = 0; !Found && j < 8; j++ ) + { + if( ( Bitmap & 0x01 ) == 0 ) + { + // + // Found... + Found = TRUE; + BlockNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 + + ( GroupNo * PtrVCB->BlocksPerGroup ); + + Bitmap = 1 << j; + PtrBitmapBuffer[i] |= Bitmap; + + CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); + // + // Should update the bitmaps in the other groups too... + // + break; + } + Bitmap = Bitmap >> 1; + } + } + } + // + // Unpin the BCB... + // + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + + } + + // + // Updating the Free Block count in the Group Descriptor... + // + + { + PBCB PtrDescriptorBCB = NULL; + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + // + // Updating the Free Blocks count in the Group Descriptor... + // + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount--; + + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrDescriptorBCB , + (PVOID*)&PtrGroupDescriptor )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + // + // Ignore this error... + // Not fatal... + } + else + { + PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; + + // + // Not synchronously flushing this information... + // Lazy writing will do... + // + CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); + CcUnpinData( PtrDescriptorBCB ); + PtrDescriptorBCB = NULL; + } + } + + // + // Update the Block count + // in the super block and in the VCB + // + { + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + + PtrVCB->FreeBlocksCount--; + + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + } + else + { + PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount; + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + if( PtrSuperBlockBCB ) + { + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + } + } + + try_exit: NOTHING; + } + finally + { + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating a block - Block no : %ld", BlockNo ); + } + return BlockNo; +} + +/************************************************************************* +* +* Function: Ext2DeallocBlock() +* +* Description: +* The functions will deallocate a data block +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2DeallocBlock( + PtrExt2IrpContext PtrIrpContext, + PtrExt2VCB PtrVCB, + ULONG BlockNo ) +{ + // Buffer Control Block + PBCB PtrBitmapBCB = NULL; + BYTE * PtrBitmapBuffer = NULL; + BOOLEAN RC = TRUE; + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + // ULONG NumberOfBytesToRead = 0; + + DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating a block - Block no : %ld", BlockNo ); + + try + { + ULONG GroupNo; + ULONG BlockIndex; + ULONG BitmapIndex; + BYTE Bitmap; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + GroupNo = BlockNo / PtrVCB->BlocksPerGroup; + BlockNo = BlockNo % PtrVCB->BlocksPerGroup; + + Bitmap = 1 << ( (BlockNo-1) % 8 ); + BitmapIndex = (BlockNo-1) / 8; + BlockIndex = BitmapIndex / LogicalBlockSize; + // Adjusting to index into the Logical block that contains the bitmap + BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize ); + + VolumeByteOffset.QuadPart = + ( PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock + BlockIndex ) + * LogicalBlockSize; + + // + // Read in the bitmap block... + // + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, // Can Wait... + &PtrBitmapBCB, + (PVOID*)&PtrBitmapBuffer ) ) + { + // Unable to Pin the data into the cache... + try_return (RC = FALSE); + } + + // + // Locate the block 'bit'... + // This block 'bit' is in the byte PtrBitmapBuffer[ BitmapIndex ] + if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0) + { + // This shouldn't have been so... + // The block was never allocated! + // How to deallocate something that hasn't been allocated? + // Hmmm... ;) + // Ignore this error... + try_return (RC = TRUE); + } + + // Setting the bit for the inode... + PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap); + + // Update the cache... + CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); + + // Save up the BCB for forcing a synchronous write... + // Before completing the IRP... + Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); + + + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + + // + // Updating the Block count in the Group Descriptor... + // + + { + PBCB PtrDescriptorBCB = NULL; + PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; + ULONG NumberOfBytesToRead = 0; + // + // Updating the Free Blocks count in the Group Descriptor... + // + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount++; + + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrDescriptorBCB , + (PVOID*)&PtrGroupDescriptor )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + // + // Ignore this error... + // Not fatal... + } + else + { + PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= + PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; + + // + // Not synchronously flushing this information... + // Lazy writing will do... + // + CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); + CcUnpinData( PtrDescriptorBCB ); + PtrDescriptorBCB = NULL; + } + } + + // + // Update the Block count + // in the super block and in the VCB + // + { + // Ext2 Super Block information... + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + ULONG NumberOfBytesToRead = 0; + + PtrVCB->FreeBlocksCount++; + + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + } + else + { + PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount; + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + } + try_exit: NOTHING; + } + finally + { + if( PtrBitmapBCB ) + { + CcUnpinData( PtrBitmapBCB ); + PtrBitmapBCB = NULL; + } + } + return RC; +} + +BOOLEAN Ext2UpdateFileSize( + PtrExt2IrpContext PtrIrpContext, + PFILE_OBJECT PtrFileObject, + PtrExt2FCB PtrFCB) +{ + EXT2_INODE Inode; + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + + if( PtrFileObject->PrivateCacheMap ) + { + CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); + } + // Now update the size on the disk... + // Read in the inode... + if( ! NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + Inode.i_size = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; + // Update time also??? + + // Updating the inode... + if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +/************************************************************************* +* +* Function: Ext2DeleteFile() +* +* Description: +* The functions will delete a file +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2DeleteFile( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext) +{ + EXT2_INODE Inode; + PtrExt2FCB PtrParentFCB = NULL; + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + + // + // Get the Parent Directory... + PtrParentFCB = Ext2LocateFCBInCore( PtrVCB, PtrFCB->ParentINodeNo ); + Ext2InitializeFCBInodeInfo( PtrFCB ); + + // 1. + // Free up the directory entry... + if( !Ext2FreeDirectoryEntry( PtrIrpContext, + PtrParentFCB, &PtrFCB->FCBName->ObjectName ) ) + { + return FALSE; + } + + // 2. + // Decrement Link count... + if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + return FALSE; + } + + ASSERT( Inode.i_links_count == PtrFCB->LinkCount ); + + Inode.i_links_count--; + PtrFCB->LinkCount = Inode.i_links_count; + + if( !Inode.i_links_count ) + { + // + // Setting the deletion time field in the inode... + // + ULONG Time; + Time = Ext2GetCurrentTime(); + Inode.i_dtime = Time ; + } + + // 3. + // Updating the inode... + + if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) + { + if( Inode.i_links_count ) + { + // Some more links to the same file are available... + // So we won't deallocate the data blocks... + return TRUE; + } + } + else + { + return FALSE; + } + + // 4. + // Free up the inode... + Ext2DeallocInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo ); + + // 5. + // Release the data blocks... + Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext); + + return TRUE; +} + + +/************************************************************************* +* +* Function: Ext2ReleaseDataBlocks() +* +* Description: +* The functions will release all the data blocks in a file +* It does NOT update the file inode... +* +* Expected Interrupt Level (for execution) : +* IRQL_PASSIVE_LEVEL +* +* Return Value: Success / Failure... +* +*************************************************************************/ +BOOLEAN Ext2ReleaseDataBlocks( + PtrExt2FCB PtrFCB, + PtrExt2IrpContext PtrIrpContext) +{ + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + ULONG LogicalBlockSize; + ULONG i; + + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + // Release the data blocks... + + // 1. + // Free up the triple indirect blocks... + if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ) + { + + PBCB PtrSIBCB = NULL; + PBCB PtrDIBCB = NULL; + PBCB PtrTIBCB = NULL; + + ULONG * PtrPinnedSIndirectBlock = NULL; + ULONG * PtrPinnedDIndirectBlock = NULL; + ULONG * PtrPinnedTIndirectBlock = NULL; + + LARGE_INTEGER VolumeByteOffset; + ULONG TIndex, DIndex, SIndex; + + // Pin the Double Indirect Pointer Block... + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrTIBCB, + (PVOID*)&PtrPinnedTIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Triple Indirect Pointer Block... + for( TIndex = 0; TIndex < (LogicalBlockSize/sizeof(ULONG)); TIndex++ ) + { + if( PtrPinnedTIndirectBlock[ TIndex ] ) + { + VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[TIndex] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrDIBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Double Indirect Pointer Blocks... + for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ ) + { + if( PtrPinnedDIndirectBlock[DIndex] ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrSIBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Single Indirect Pointer Blocks and + // free the data blocks + for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ ) + { + if( PtrPinnedSIndirectBlock[ SIndex ] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] ); + } + else + { + break; + } + } + CcUnpinData( PtrSIBCB ); + + // Deallocating + // Single Indirect Pointer Block + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] ); + } + else + { + break; + } + } + } + else + { + break; + } + } + CcUnpinData( PtrTIBCB ); + // Deallocating Triple Indirect Pointer Blocks + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ); + } + + // 2. + // Free up the double indirect blocks... + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ) + { + PBCB PtrDIBCB = NULL; + PBCB PtrSIBCB = NULL; + ULONG * PtrPinnedSIndirectBlock = NULL; + ULONG * PtrPinnedDIndirectBlock = NULL; + + LARGE_INTEGER VolumeByteOffset; + ULONG DIndex, SIndex; + + // Pin the Double Indirect Pointer Block... + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrDIBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Double Indirect Pointer Block... + for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ ) + { + if( PtrPinnedDIndirectBlock[DIndex] ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrSIBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Single Indirect Pointer Blocks and + // free the data blocks + for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ ) + { + if( PtrPinnedSIndirectBlock[ SIndex ] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] ); + } + else + { + break; + } + } + CcUnpinData( PtrSIBCB ); + + // Deallocating + // Single Indirect Pointer Block + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] ); + } + else + { + break; + } + } + CcUnpinData( PtrDIBCB ); + // Deallocating Double Indirect Pointer Blocks + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ); + } + + // 3. + // Free up the single indirect blocks... + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) + { + PBCB PtrBCB = NULL; + ULONG * PtrPinnedSIndirectBlock = NULL; + LARGE_INTEGER VolumeByteOffset; + ULONG Index; + + // Pin the Single Indirect Pointer Block... + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Indirect Pointer Block and + // free the data blocks + for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); Index++ ) + { + if( PtrPinnedSIndirectBlock[Index] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] ); + } + else + { + break; + } + } + CcUnpinData( PtrBCB ); + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] ); + } + + // 4. + // Free up the direct blocks... + for( i = 0; i < EXT2_NDIR_BLOCKS; i++ ) + { + if( PtrFCB->IBlock[ i ] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] ); + } + else + { + break; + } + } + return TRUE; +} + + +BOOLEAN Ext2TruncateFileAllocationSize( + PtrExt2IrpContext PtrIrpContext, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject, + PLARGE_INTEGER PtrAllocationSize ) +{ + PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; + ULONG LogicalBlockSize; + ULONG i; + + ULONG NoOfBlocksToBeLeft= 0; + ULONG CurrentBlockNo = 0; + + // + // This function has not been tested... + // + Ext2BreakPoint(); + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + NoOfBlocksToBeLeft = (ULONG) (PtrAllocationSize->QuadPart / LogicalBlockSize); + + + + // Release the data blocks... + + // 1. + // Free up the direct blocks... + for( i = NoOfBlocksToBeLeft; i < EXT2_NDIR_BLOCKS; i++ ) + { + if( PtrFCB->IBlock[ i ] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] ); + PtrFCB->IBlock[ i ] = 0; + } + else + { + break; + } + } + + // 2. + // Free up the single indirect blocks... + CurrentBlockNo = EXT2_NDIR_BLOCKS; + + if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) + { + PBCB PtrBCB = NULL; + ULONG * PtrPinnedSIndirectBlock = NULL; + LARGE_INTEGER VolumeByteOffset; + ULONG Index; + + // Pin the Single Indirect Pointer Block... + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + return FALSE; + } + + // Read the Block numbers off the Indirect Pointer Block and + // free the data blocks + for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); + Index++, CurrentBlockNo++ ) + { + if( CurrentBlockNo >= NoOfBlocksToBeLeft ) + { + if( PtrPinnedSIndirectBlock[Index] ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] ); + } + else + { + break; + } + } + else if( !PtrPinnedSIndirectBlock[Index] ) + { + break; + } + } + if( NoOfBlocksToBeLeft <= EXT2_NDIR_BLOCKS ) + { + Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] ); + PtrFCB->IBlock[ EXT2_IND_BLOCK ] = 0; + } + + CcUnpinData( PtrBCB ); + } + + // 3. + // Free up the double indirect blocks... + if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ) + { + + } + + // 4. + // Free up the triple indirect blocks... + if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ) + { + + } + + return TRUE; +} + +BOOLEAN Ext2IsDirectoryEmpty( + PtrExt2FCB PtrFCB, + PtrExt2CCB PtrCCB, + PtrExt2IrpContext PtrIrpContext) +{ + + PFILE_OBJECT PtrFileObject = NULL; + + if( !Ext2IsFlagOn(PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY) ) + { + return FALSE; + } + + // 1. + // Initialize the Blocks in the FCB... + // + Ext2InitializeFCBInodeInfo( PtrFCB ); + + + // 2. + // Get hold of the file object... + // + PtrFileObject = PtrCCB->PtrFileObject; + + + // 3. + // Now initiating Caching, pinned access to be precise ... + // + if (PtrFileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrFCB ); // The context used in callbacks + } + + // 4. + // Getting down to the real business now... ;) + // Read in the directory contents and do a search + // + { + LARGE_INTEGER StartBufferOffset; + ULONG PinBufferLength; + ULONG BufferIndex; + PBCB PtrBCB = NULL; + BYTE * PtrPinnedBlockBuffer = NULL; + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + BOOLEAN Found = FALSE; + int i; + + + + StartBufferOffset.QuadPart = 0; + + // + // Read in the whole directory + // **Bad programming** + // Will do for now. + // + PinBufferLength = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; + if (!CcMapData( PtrFileObject, + &StartBufferOffset, + PinBufferLength, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedBlockBuffer ) ) + { + return FALSE; + } + + // + // Walking through now... + // + for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) + { + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; + if( PtrDirEntry->inode == 0) + { + // Deleted entry... + // Ignore... + continue; + } + if( PtrDirEntry->name[0] == '.' ) + { + if( PtrDirEntry->name_len == 1 || + ( PtrDirEntry->name_len == 2 && PtrDirEntry->name[1] == '.' ) ) + { + continue; + } + } + Found = TRUE; + } + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + + return !Found; + } +} + + +NTSTATUS Ext2RenameOrLinkFile( + PtrExt2FCB PtrSourceFCB, + PFILE_OBJECT PtrSourceFileObject, + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PFILE_RENAME_INFORMATION PtrRenameInfo) +{ + PtrExt2FCB PtrParentFCB = NULL; + PtrExt2VCB PtrSourceVCB = PtrSourceFCB->PtrVCB; + + PtrExt2FCB PtrTargetFCB = NULL; + PtrExt2CCB PtrTargetCCB = NULL; + PtrExt2VCB PtrTargetVCB = NULL; + + + FILE_INFORMATION_CLASS FunctionalityRequested; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + PFILE_OBJECT TargetFileObject = NULL; + BOOLEAN ReplaceExistingFile = FALSE; + BOOLEAN Found = FALSE; + + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass; + TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject; + ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists; + + // Get the FCB and CCB pointers + Ext2GetFCB_CCB_VCB_FromFileObject ( + TargetFileObject , &PtrTargetFCB, &PtrTargetCCB, &PtrTargetVCB); + + if( !PtrTargetCCB ) + { + return STATUS_ACCESS_DENIED; + } + if( PtrTargetVCB != PtrSourceVCB ) + { + // Cannot rename across volumes... + return STATUS_ACCESS_DENIED; + } + if ( !Ext2IsFlagOn( PtrTargetFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + // Target has to be a folder... + return STATUS_ACCESS_DENIED; + } + + // 1. + // Open the parent folder... + PtrParentFCB = Ext2LocateFCBInCore( PtrSourceVCB, PtrSourceFCB->ParentINodeNo ); + if( !PtrParentFCB ) + { + // Get the folder from the disk + // Use the inode no PtrSourceFCB->ParentINodeNo + // + // For now... + return STATUS_ACCESS_DENIED; + } + + // 2. + // Check if the file exists in the TargetFolder... + { + LARGE_INTEGER StartBufferOffset; + ULONG PinBufferLength; + ULONG BufferIndex; + PBCB PtrBCB = NULL; + BYTE * PtrPinnedBlockBuffer = NULL; + PEXT2_DIR_ENTRY PtrDirEntry = NULL; + int i; + + StartBufferOffset.QuadPart = 0; + + // + // Read in the whole directory + // + if ( TargetFileObject->PrivateCacheMap == NULL ) + { + CcInitializeCacheMap( + TargetFileObject, + (PCC_FILE_SIZES)(&(PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), + TRUE, // We utilize pin access for directories + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrTargetCCB ); // The context used in callbacks + } + + PinBufferLength = PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; + if (!CcMapData( TargetFileObject, + &StartBufferOffset, + PinBufferLength, + TRUE, + &PtrBCB, + (PVOID*)&PtrPinnedBlockBuffer ) ) + { + return FALSE; + } + + // + // Walking through now... + // + for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) + { + PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; + if( PtrDirEntry->inode == 0) + { + // Deleted entry... + // Ignore... + continue; + } + if( PtrDirEntry->name_len == (PtrTargetCCB->RenameLinkTargetFileName.Length/2) ) + { + Found = TRUE; + for( i =0; i < PtrDirEntry->name_len ; i++ ) + { + if( PtrDirEntry->name[i] != PtrTargetCCB->RenameLinkTargetFileName.Buffer[i] ) + { + Found = FALSE; + break; + } + } + } + } + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } + + // 3. + // If the file exists, delete it if requested.. + if( Found ) + { + if( !ReplaceExistingFile ) + { + return STATUS_OBJECT_NAME_COLLISION; + } + // Delete the file... + // Reject this for now... + return STATUS_ACCESS_DENIED; + } + + + { + ULONG Type = EXT2_FT_REG_FILE; + if( Ext2IsFlagOn( PtrSourceFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) + { + Type = EXT2_FT_DIR; + } + + ASSERT( TargetFileObject ); + + // 4. + // Remove the old entry... + Ext2FreeDirectoryEntry( PtrIrpContext, PtrParentFCB, + &PtrSourceFCB->FCBName->ObjectName); + + // 5. + // Create a new entry... + Ext2MakeNewDirectoryEntry( + PtrIrpContext, // This IRP Context + PtrTargetFCB, // Parent Folder FCB + TargetFileObject, // Parent Folder Object + &PtrTargetCCB->RenameLinkTargetFileName, // New entry's name + Type, // The type of the new entry + PtrSourceFCB->INodeNo ); // The inode no of the new entry... + + } + + // 6. + // Update the PtrSourceFCB... + { + + PtrExt2ObjectName PtrObjectName; + if( PtrSourceFCB->FCBName ) + { + Ext2ReleaseObjectName( PtrSourceFCB->FCBName ); + } + PtrObjectName = Ext2AllocateObjectName(); + Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &PtrTargetCCB->RenameLinkTargetFileName ); + PtrSourceFCB->FCBName = PtrObjectName; + PtrSourceFCB->ParentINodeNo = PtrTargetFCB->INodeNo; + } + + if( PtrTargetCCB->RenameLinkTargetFileName.Length ) + { + Ext2DeallocateUnicodeString( &PtrTargetCCB->RenameLinkTargetFileName ); + } + + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/filesystems/ext2/src/misc.c b/reactos/drivers/filesystems/ext2/src/misc.c new file mode 100644 index 00000000000..fd9c98099f0 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/misc.c @@ -0,0 +1,2116 @@ +/************************************************************************* +* +* File: misc.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* This file contains some miscellaneous support routines. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_MISC + +#define DEBUG_LEVEL ( DEBUG_TRACE_MISC ) + +/************************************************************************* +* +* Function: Ext2InitializeZones() +* +* Description: +* Allocates some memory for global zones used to allocate FSD structures. +* Either all memory will be allocated or we will back out gracefully. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2InitializeZones( +void) +{ + NTSTATUS RC = STATUS_SUCCESS; + uint32 SizeOfZone = Ext2GlobalData.DefaultZoneSizeInNumStructs; + uint32 SizeOfObjectNameZone = 0; + uint32 SizeOfCCBZone = 0; + uint32 SizeOfFCBZone = 0; + uint32 SizeOfByteLockZone = 0; + uint32 SizeOfIrpContextZone = 0; + + try { + + // initialize the spinlock protecting the zones + KeInitializeSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock)); + + // determine memory requirements + switch (MmQuerySystemSize()) { + case MmSmallSystem: + // this is just for illustration purposes. I will multiply + // number of structures with some arbitrary amount depending + // upon available memory in the system ... You should choose a + // more intelligent method suitable to your memory consumption + // and the amount of memory available. + SizeOfObjectNameZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfFCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfByteLockZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + break; + case MmMediumSystem: + SizeOfObjectNameZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfFCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfByteLockZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + break; + case MmLargeSystem: + SizeOfObjectNameZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfCCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfFCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfByteLockZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); + SizeOfIrpContextZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); + break; + } + + // typical NT methodology (at least until *someone* exposed the "difference" between a server and workstation ;-) + if (MmIsThisAnNtAsSystem()) { + SizeOfObjectNameZone *= EXT2_NTAS_MULTIPLE; + SizeOfCCBZone *= EXT2_NTAS_MULTIPLE; + SizeOfFCBZone *= EXT2_NTAS_MULTIPLE; + SizeOfByteLockZone *= EXT2_NTAS_MULTIPLE; + SizeOfIrpContextZone *= EXT2_NTAS_MULTIPLE; + } + + // allocate memory for each of the zones and initialize the zones ... + if (!(Ext2GlobalData.ObjectNameZone = Ext2AllocatePool(NonPagedPool, SizeOfObjectNameZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(Ext2GlobalData.CCBZone = Ext2AllocatePool(NonPagedPool, SizeOfCCBZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(Ext2GlobalData.FCBZone = Ext2AllocatePool(NonPagedPool, SizeOfFCBZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(Ext2GlobalData.ByteLockZone = Ext2AllocatePool(NonPagedPool, SizeOfByteLockZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + if (!(Ext2GlobalData.IrpContextZone = Ext2AllocatePool(NonPagedPool, SizeOfIrpContextZone ))) { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + // initialize each of the zone headers ... + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ObjectNameZoneHeader), + Ext2QuadAlign(sizeof(Ext2ObjectName)), + Ext2GlobalData.ObjectNameZone, SizeOfObjectNameZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.CCBZoneHeader), + Ext2QuadAlign(sizeof(Ext2CCB)), + Ext2GlobalData.CCBZone, + SizeOfCCBZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.FCBZoneHeader), + Ext2QuadAlign(sizeof(Ext2FCB)), + Ext2GlobalData.FCBZone, + SizeOfFCBZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ByteLockZoneHeader), + Ext2QuadAlign(sizeof(Ext2FileLockInfo)), + Ext2GlobalData.ByteLockZone, + SizeOfByteLockZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.IrpContextZoneHeader), + Ext2QuadAlign(sizeof(Ext2IrpContext)), + Ext2GlobalData.IrpContextZone, + SizeOfIrpContextZone))) { + // failed the initialization, leave ... + try_return(RC); + } + + try_exit: NOTHING; + + } finally { + if (!NT_SUCCESS(RC)) { + // invoke the destroy routine now ... + Ext2DestroyZones(); + } else { + // mark the fact that we have allocated zones ... + Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED); + } + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2DestroyZones() +* +* Description: +* Free up the previously allocated memory. NEVER do this once the +* driver has been successfully loaded. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2DestroyZones( +void) +{ + try { + // free up each of the pools + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.ObjectNameZone); + ExFreePool(Ext2GlobalData.ObjectNameZone); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.CCBZone); + ExFreePool(Ext2GlobalData.CCBZone); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.FCBZone); + ExFreePool(Ext2GlobalData.FCBZone); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.ByteLockZone); + ExFreePool(Ext2GlobalData.ByteLockZone); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.IrpContextZone); + ExFreePool(Ext2GlobalData.IrpContextZone); + + try_exit: NOTHING; + + } + finally + { + Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED); + } + + return; +} + + +/************************************************************************* +* +* Function: Ext2IsIrpTopLevel() +* +* Description: +* Helps the FSD determine who the "top level" caller is for this +* request. A request can originate directly from a user process +* (in which case, the "top level" will be NULL when this routine +* is invoked), OR the user may have originated either from the NT +* Cache Manager/VMM ("top level" may be set), or this could be a +* recursion into our code in which we would have set the "top level" +* field the last time around. +* +* Expected Interrupt Level (for execution) : +* +* whatever level a particular dispatch routine is invoked at. +* +* Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked) +* +*************************************************************************/ +BOOLEAN Ext2IsIrpTopLevel( +PIRP Irp) // the IRP sent to our dispatch routine +{ + BOOLEAN ReturnCode = FALSE; + + if (IoGetTopLevelIrp() == NULL) + { + // OK, so we can set ourselves to become the "top level" component + IoSetTopLevelIrp( Irp ); + ReturnCode = TRUE; + } + + return(ReturnCode); +} + + +/************************************************************************* +* +* Function: Ext2ExceptionFilter() +* +* Description: +* This routines allows the driver to determine whether the exception +* is an "allowed" exception i.e. one we should not-so-quietly consume +* ourselves, or one which should be propagated onwards in which case +* we will most likely bring down the machine. +* +* This routine employs the services of FsRtlIsNtstatusExpected(). This +* routine returns a BOOLEAN result. A RC of FALSE will cause us to return +* EXCEPTION_CONTINUE_SEARCH which will probably cause a panic. +* The FsRtl.. routine returns FALSE iff exception values are (currently) : +* STATUS_DATATYPE_MISALIGNMENT || STATUS_ACCESS_VIOLATION || +* STATUS_ILLEGAL_INSTRUCTION || STATUS_INSTRUCTION_MISALIGNMENT +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH +* +*************************************************************************/ +long Ext2ExceptionFilter( +PtrExt2IrpContext PtrIrpContext, +PEXCEPTION_POINTERS PtrExceptionPointers ) +{ + long ReturnCode = EXCEPTION_EXECUTE_HANDLER; + NTSTATUS ExceptionCode = STATUS_SUCCESS; + + // figure out the exception code + ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode; + + if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3)) + { + ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2]; + } + + if (PtrIrpContext) + { + PtrIrpContext->SavedExceptionCode = ExceptionCode; + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_EXCEPTION); + } + + // check if we should propagate this exception or not + if (!(FsRtlIsNtstatusExpected(ExceptionCode))) + { + // we are not ok, propagate this exception. + // NOTE: we will bring down the machine ... + ReturnCode = EXCEPTION_CONTINUE_SEARCH; + + // better free up the IrpContext now ... + if (PtrIrpContext) + { + Ext2ReleaseIrpContext(PtrIrpContext); + } + } + + // if you wish to perform some special processing when + // not propagating the exception, set up the state for + // special processing now ... + + // return the appropriate code + return(ReturnCode); +} + +/************************************************************************* +* +* Function: Ext2ExceptionHandler() +* +* Description: +* One of the routines in the FSD or in the modules we invoked encountered +* an exception. We have decided that we will "handle" the exception. +* Therefore we will prevent the machine from a panic ... +* You can do pretty much anything you choose to in your commercial +* driver at this point to ensure a graceful exit. In the sample +* driver, I will simply free up the IrpContext (if any), set the +* error code in the IRP and complete the IRP at this time ... +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: Error code +* +*************************************************************************/ +NTSTATUS Ext2ExceptionHandler( +PtrExt2IrpContext PtrIrpContext, +PIRP Irp) +{ + NTSTATUS RC; + + ASSERT(Irp); + + if (PtrIrpContext) + { + RC = PtrIrpContext->SavedExceptionCode; + // Free irp context here + Ext2ReleaseIrpContext(PtrIrpContext); + } + else + { + // must be insufficient resources ...? + RC = STATUS_INSUFFICIENT_RESOURCES; + } + + // set the error code in the IRP + Irp->IoStatus.Status = RC; + Irp->IoStatus.Information = 0; + + // complete the IRP + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return(RC); +} + +/************************************************************************* +* +* Function: Ext2LogEvent() +* +* Description: +* Log a message in the NT Event Log. This is a rather simplistic log +* methodology since you can potentially utilize the event log to +* provide a lot of information to the user (and you should too!) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2LogEvent( +NTSTATUS Ext2EventLogId, // the Ext2 private message id +NTSTATUS RC) // any NT error code we wish to log ... +{ + try + { + + // Implement a call to IoAllocateErrorLogEntry() followed by a call + // to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry() + // will free memory for the entry once the write completes (which in actuality + // is an asynchronous operation). + + } + except (EXCEPTION_EXECUTE_HANDLER) + { + // nothing really we can do here, just do not wish to crash ... + NOTHING; + } + + return; +} + +/************************************************************************* +* +* Function: Ext2AllocateObjectName() +* +* Description: +* Allocate a new ObjectName structure to represent an open on-disk object. +* Also initialize the ObjectName structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the ObjectName structure OR NULL. +* +*************************************************************************/ +PtrExt2ObjectName Ext2AllocateObjectName( +void) +{ + PtrExt2ObjectName PtrObjectName = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; +/* + // first, try to allocate out of the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.ObjectNameZoneHeader))) { + // we have enough memory + PtrObjectName = (PtrExt2ObjectName)ExAllocateFromZone(&(Ext2GlobalData.ObjectNameZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + + // if we failed to obtain from the zone, get it directly from the VMM +*/ + PtrObjectName = (PtrExt2ObjectName)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2ObjectName)) ); + AllocatedFromZone = FALSE; +/* + } +*/ + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrObjectName) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2ObjectName)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory( PtrObjectName, Ext2QuadAlign(sizeof(Ext2ObjectName)) ); + + // set up some fields ... + PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_OBJECT_NAME; + PtrObjectName->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2ObjectName)); + + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrObjectName->ObjectNameFlags, EXT2_OB_NAME_NOT_FROM_ZONE); + } + + return(PtrObjectName); +} + + +/************************************************************************* +* +* Function: Ext2ReleaseObjectName() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseObjectName( +PtrExt2ObjectName PtrObjectName) +{ + KIRQL CurrentIrql; + + ASSERT(PtrObjectName); + PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; +#ifdef USE_ZONES + + // give back memory either to the zone or to the VMM + if (!(PtrObjectName->ObjectNameFlags & EXT2_OB_NAME_NOT_FROM_ZONE)) + { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.ObjectNameZoneHeader), PtrObjectName); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { +#endif + + Ext2DeallocateUnicodeString( & PtrObjectName->ObjectName ); + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrObjectName); + ExFreePool(PtrObjectName); + +#ifdef USE_ZONES + } +#endif + return; +} + +/************************************************************************* +* +* Function: Ext2AllocateCCB() +* +* Description: +* Allocate a new CCB structure to represent an open on-disk object. +* Also initialize the CCB structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the CCB structure OR NULL. +* +*************************************************************************/ +PtrExt2CCB Ext2AllocateCCB( +void) +{ + PtrExt2CCB PtrCCB = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + + +#ifdef USE_ZONES + // first, try to allocate out of the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.CCBZoneHeader))) + { + // we have enough memory + PtrCCB = (PtrExt2CCB)ExAllocateFromZone(&(Ext2GlobalData.CCBZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + // if we failed to obtain from the zone, get it directly from the VMM +#endif + + PtrCCB = (PtrExt2CCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2CCB)) ); + AllocatedFromZone = FALSE; + +#ifdef USE_ZONES + } +#endif + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrCCB) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2CCB)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory(PtrCCB, Ext2QuadAlign(sizeof(Ext2CCB))); + + // set up some fields ... + PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_CCB; + PtrCCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2CCB)); + + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_NOT_FROM_ZONE); + } + + return(PtrCCB); +} + +/************************************************************************* +* +* Function: Ext2ReleaseCCB() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseCCB( +PtrExt2CCB PtrCCB) +{ + KIRQL CurrentIrql; + + ASSERT( PtrCCB ); + if(PtrCCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_CCB) + { + Ext2Panic( PtrCCB, PtrCCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_CCB ) ; + } + + Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); + Ext2DeallocateUnicodeString( &PtrCCB->AbsolutePathName ); + Ext2DeallocateUnicodeString( &PtrCCB->RenameLinkTargetFileName ); + + +#ifdef USE_ZONES + + // give back memory either to the zone or to the VMM + if (!(PtrCCB->CCBFlags & EXT2_CCB_NOT_FROM_ZONE)) + { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.CCBZoneHeader), PtrCCB); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { +#endif + PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrCCB); + ExFreePool(PtrCCB); + +#ifdef USE_ZONES + } +#endif + + return; +} + +/************************************************************************* +* +* Function: Ext2AllocateFCB() +* +* Description: +* Allocate a new FCB structure to represent an open on-disk object. +* Also initialize the FCB structure to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the FCB structure OR NULL. +* +*************************************************************************/ +PtrExt2FCB Ext2AllocateFCB( +void) +{ + PtrExt2FCB PtrFCB = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + + // first, try to allocate out of the zone +#ifdef USE_ZONES + + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.FCBZoneHeader))) { + // we have enough memory + PtrFCB = (PtrExt2FCB)ExAllocateFromZone(&(Ext2GlobalData.FCBZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); +#endif + // if we failed to obtain from the zone, get it directly from the VMM + PtrFCB = (PtrExt2FCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FCB)) ); + AllocatedFromZone = FALSE; + +#ifdef USE_ZONES + } +#endif + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrFCB) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FCB)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB))); + + // set up some fields ... + PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB; + PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB)); + + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE); + } + + return(PtrFCB); +} + + +/************************************************************************* +* +* Function: Ext2CreateNewFCB() +* +* Description: +* We want to create a new FCB. We will also create a new CCB (presumably) +* later. Simply allocate a new FCB structure and initialize fields +* appropriately. +* This function also takes the file size values that the caller must +* have obtained and will set the file size fields appropriately in the +* CommonFCBHeader. +* Finally, this routine will initialize the FileObject structure passed +* in to this function. If you decide to fail the call later, remember +* to uninitialize the fields. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the FCB structure OR NULL. +* +*************************************************************************/ +NTSTATUS Ext2CreateNewFCB( +PtrExt2FCB *ReturnedFCB, +LARGE_INTEGER AllocationSize, +LARGE_INTEGER EndOfFile, +PFILE_OBJECT PtrFileObject, +PtrExt2VCB PtrVCB, +PtrExt2ObjectName PtrObjectName) +{ + NTSTATUS RC = STATUS_SUCCESS; + + PtrExt2FCB PtrFCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PFSRTL_COMMON_FCB_HEADER PtrCommonFCBHeader = NULL; + + ASSERT( PtrVCB ); + + try + { + if( !PtrFileObject ) + { + PtrFCB = Ext2GetUsedFCB( PtrVCB ); + + } + else + { + // Obtain a new FCB structure. + // The function Ext2AllocateFCB() will obtain a new structure either + // from a zone or from memory requested directly from the VMM. + PtrFCB = Ext2AllocateFCB(); + } + if (!PtrFCB) + { + // Assume lack of memory. + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + + // Initialize fields required to interface with the NT Cache Manager. + // Note that the returned structure has already been zeroed. This means + // that the SectionObject structure has been zeroed which is a + // requirement for newly created FCB structures. + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Initialize the MainResource and PagingIoResource structures now. + ExInitializeResourceLite(&(PtrReqdFCB->MainResource)); + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_MAIN_RESOURCE); + + ExInitializeResourceLite(&(PtrReqdFCB->PagingIoResource)); + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_PAGING_IO_RESOURCE); + + // Start initializing the fields contained in the CommonFCBHeader. + PtrCommonFCBHeader = &(PtrReqdFCB->CommonFCBHeader); + + // Disallow fast-IO for now. + PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible; + + // Initialize the MainResource and PagingIoResource pointers in + // the CommonFCBHeader structure to point to the ERESOURCE structures we + // have allocated and already initialized above. + PtrCommonFCBHeader->Resource = &(PtrReqdFCB->MainResource); + PtrCommonFCBHeader->PagingIoResource = &(PtrReqdFCB->PagingIoResource); + + // Ignore the Flags field in the CommonFCBHeader for now. Part 3 + // of the book describes it in greater detail. + + // Initialize the file size values here. + PtrCommonFCBHeader->AllocationSize = AllocationSize; + PtrCommonFCBHeader->FileSize = EndOfFile; + + // The following will disable ValidDataLength support. However, your + // FSD may choose to support this concept. + PtrCommonFCBHeader->ValidDataLength.LowPart = 0xFFFFFFFF; + PtrCommonFCBHeader->ValidDataLength.HighPart = 0x7FFFFFFF; + + // Initialize other fields for the FCB here ... + PtrFCB->PtrVCB = PtrVCB; + + // caller MUST ensure that VCB has been acquired exclusively + InsertTailList(&(PtrVCB->FCBListHead), &(PtrFCB->NextFCB)); + + + InitializeListHead(&(PtrFCB->CCBListHead)); + + // Initialize fields contained in the file object now. + if( PtrFileObject ) + { + PtrFileObject->PrivateCacheMap = NULL; + // Note that we could have just as well taken the value of PtrReqdFCB + // directly below. The bottom line however is that the FsContext + // field must point to a FSRTL_COMMON_FCB_HEADER structure. + PtrFileObject->FsContext = (void *)(PtrCommonFCBHeader); + PtrFileObject->SectionObjectPointer = &(PtrFCB->NTRequiredFCB.SectionObject) ; + } + + // Initialising the object name... + PtrFCB->FCBName = PtrObjectName; + + // Returning the FCB... + *ReturnedFCB = PtrFCB; + try_exit: NOTHING; + } + + finally + { + + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2ReleaseFCB() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseFCB( +PtrExt2FCB PtrFCB) +{ + KIRQL CurrentIrql; + + AssertFCB( PtrFCB ); + + if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) + { + Ext2Panic( PtrFCB, PtrFCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_FCB ) ; + } + + + PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; + + /* + // give back memory either to the zone or to the VMM + if (!(PtrFCB->FCBFlags & EXT2_FCB_NOT_FROM_ZONE)) + { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.FCBZoneHeader), PtrFCB); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + */ + + ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource ); + ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource ); + + if( PtrFCB->FCBName ) + { + Ext2ReleaseObjectName( PtrFCB->FCBName ); + } + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrFCB); + ExFreePool(PtrFCB); + + /* + } + */ + + return; +} + +/************************************************************************* +* +* Function: Ext2AllocateByteLocks() +* +* Description: +* Allocate a new byte range lock structure and initialize it to NULL. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the Ext2ByteLocks structure OR NULL. +* +*************************************************************************/ +PtrExt2FileLockInfo Ext2AllocateByteLocks( +void) +{ + PtrExt2FileLockInfo PtrByteLocks = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + + // first, try to allocate out of the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.ByteLockZoneHeader))) + { + // we have enough memory + PtrByteLocks = (PtrExt2FileLockInfo)ExAllocateFromZone(&(Ext2GlobalData.ByteLockZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + + // if we failed to obtain from the zone, get it directly from the VMM + PtrByteLocks = (PtrExt2FileLockInfo)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FileLockInfo)) ); + AllocatedFromZone = FALSE; + } + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrByteLocks) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FileLockInfo)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory(PtrByteLocks, Ext2QuadAlign(sizeof(PtrExt2FileLockInfo))); + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrByteLocks->FileLockFlags, EXT2_BYTE_LOCK_NOT_FROM_ZONE); + } + + return(PtrByteLocks); +} + +/************************************************************************* +* +* Function: Ext2ReleaseByteLocks() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseByteLocks( +PtrExt2FileLockInfo PtrByteLocks) +{ + KIRQL CurrentIrql; + + ASSERT(PtrByteLocks); + + // give back memory either to the zone or to the VMM + if (!(PtrByteLocks->FileLockFlags & EXT2_BYTE_LOCK_NOT_FROM_ZONE)) { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.ByteLockZoneHeader), PtrByteLocks); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrByteLocks); + ExFreePool(PtrByteLocks); + } + + return; +} + + +/************************************************************************* +* +* Function: Ext2AllocateIrpContext() +* +* Description: +* The sample FSD creates an IRP context for each request received. This +* routine simply allocates (and initializes to NULL) a Ext2IrpContext +* structure. +* Most of the fields in the context structure are then initialized here. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the IrpContext structure OR NULL. +* +*************************************************************************/ +PtrExt2IrpContext Ext2AllocateIrpContext( +PIRP Irp, +PDEVICE_OBJECT PtrTargetDeviceObject) +{ + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AllocatedFromZone = TRUE; + KIRQL CurrentIrql; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + + /* + // Allocation from zone not done at present... + + // first, try to allocate out of the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + if (!ExIsFullZone(&(Ext2GlobalData.IrpContextZoneHeader))) { + // we have enough memory + PtrIrpContext = (PtrExt2IrpContext)ExAllocateFromZone(&(Ext2GlobalData.IrpContextZoneHeader)); + + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } else { + // release the spinlock + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + + + + + // if we failed to obtain from the zone, get it directly from the VMM + PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) ); + AllocatedFromZone = FALSE; + } + + //No Zone handling for now + */ + + PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) ); + AllocatedFromZone = FALSE; + + // if we could not obtain the required memory, bug-check. + // Do NOT do this in your commercial driver, instead handle the error gracefully ... + if (!PtrIrpContext) + { + Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2IrpContext)), 0); + } + + // zero out the allocated memory block + RtlZeroMemory(PtrIrpContext, Ext2QuadAlign(sizeof(Ext2IrpContext))); + + // set up some fields ... + PtrIrpContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IRP_CONTEXT; + PtrIrpContext->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2IrpContext)); + + + PtrIrpContext->Irp = Irp; + PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject; + + // copy over some fields from the IRP and set appropriate flag values + if (Irp) + { + PtrIoStackLocation = IoGetCurrentIrpStackLocation(Irp); + ASSERT(PtrIoStackLocation); + + PtrIrpContext->MajorFunction = PtrIoStackLocation->MajorFunction; + PtrIrpContext->MinorFunction = PtrIoStackLocation->MinorFunction; + + // Often, a FSD cannot honor a request for asynchronous processing + // of certain critical requests. For example, a "close" request on + // a file object can typically never be deferred. Therefore, do not + // be surprised if sometimes your FSD (just like all other FSD + // implementations on the Windows NT system) has to override the flag + // below. + if( PtrIoStackLocation->FileObject ) + { + if (IoIsOperationSynchronous(Irp) ) + { + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); + } + } + else + { + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); + } + } + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_FROM_ZONE); + } + + // Are we top-level ? This information is used by the dispatching code + // later (and also by the FSD dispatch routine) + if (IoGetTopLevelIrp() != Irp) + { + // We are not top-level. Note this fact in the context structure + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_TOP_LEVEL); + } + + InitializeListHead( &PtrIrpContext->SavedBCBsListHead ); + + return(PtrIrpContext); +} + + +/************************************************************************* +* +* Function: Ext2ReleaseIrpContext() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2ReleaseIrpContext( +PtrExt2IrpContext PtrIrpContext) +{ + KIRQL CurrentIrql; + + ASSERT(PtrIrpContext); + + // Flush the saved BCBs... + Ext2FlushSavedBCBs( PtrIrpContext ); + + // give back memory either to the zone or to the VMM + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_FROM_ZONE)) + { + // back to the zone + KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); + ExFreeToZone(&(Ext2GlobalData.IrpContextZoneHeader), PtrIrpContext); + KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); + } + else + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrIrpContext); + ExFreePool(PtrIrpContext); + } + + return; +} + +/************************************************************************* +* +* Function: Ext2PostRequest() +* +* Description: +* Queue up a request for deferred processing (in the context of a system +* worker thread). The caller must have locked the user buffer (if required) +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_PENDING +* +*************************************************************************/ +NTSTATUS Ext2PostRequest( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_PENDING; + + DebugTrace(DEBUG_TRACE_ASYNC, " === Asynchronous request. Deferring processing", 0); + + // mark the IRP pending + IoMarkIrpPending(PtrIrp); + + // queue up the request + ExInterlockedInsertTailList( + &Ext2GlobalData.ThreadQueue.ThreadQueueListHead, + &PtrIrpContext->ThreadQueueListEntry, + &Ext2GlobalData.ThreadQueue.SpinLock ); + + KeSetEvent( &Ext2GlobalData.ThreadQueue.QueueEvent, 0, FALSE ); + + +/***************** not using system worker threads ***************** + ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), Ext2CommonDispatch, PtrIrpContext); + ExQueueWorkItem( &( PtrIrpContext->WorkQueueItem ), DelayedWorkQueue ); + // CriticalWorkQueue +*****************************************************************************/ + + // return status pending + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonDispatch() +* +* Description: +* The common dispatch routine invoked in the context of a system worker +* thread. All we do here is pretty much case off the major function +* code and invoke the appropriate FSD dispatch routine for further +* processing. +* +* Expected Interrupt Level (for execution) : +* +* IRQL PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2CommonDispatch( + void *Context ) // actually an IRPContext structure +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + PIRP PtrIrp = NULL; + + // The context must be a pointer to an IrpContext structure + PtrIrpContext = (PtrExt2IrpContext)Context; + ASSERT(PtrIrpContext); + + // Assert that the Context is legitimate + if ((PtrIrpContext->NodeIdentifier.NodeType != EXT2_NODE_TYPE_IRP_CONTEXT) || (PtrIrpContext->NodeIdentifier.NodeSize != Ext2QuadAlign(sizeof(Ext2IrpContext)))) + { + // This does not look good + Ext2Panic(EXT2_ERROR_INTERNAL_ERROR, PtrIrpContext->NodeIdentifier.NodeType, PtrIrpContext->NodeIdentifier.NodeSize); + } + + // Get a pointer to the IRP structure + PtrIrp = PtrIrpContext->Irp; + ASSERT(PtrIrp); + + // Now, check if the FSD was top level when the IRP was originally invoked + // and set the thread context (for the worker thread) appropriately + if (PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_TOP_LEVEL) + { + // The FSD is not top level for the original request + // Set a constant value in TLS to reflect this fact + IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); + } + + // Since the FSD routine will now be invoked in the context of this worker + // thread, we should inform the FSD that it is perfectly OK to block in + // the context of this thread + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); + + FsRtlEnterFileSystem(); + + try + { + + // Pre-processing has been completed; check the Major Function code value + // either in the IrpContext (copied from the IRP), or directly from the + // IRP itself (we will need a pointer to the stack location to do that), + // Then, switch based on the value on the Major Function code + switch (PtrIrpContext->MajorFunction) + { + case IRP_MJ_CREATE: + // Invoke the common create routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CREATE request asynchronously .", 0); + (void)Ext2CommonCreate(PtrIrpContext, PtrIrp, FALSE); + break; + case IRP_MJ_READ: + // Invoke the common read routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_READ request asynchronously .", 0); + (void)Ext2CommonRead(PtrIrpContext, PtrIrp, FALSE); + break; + case IRP_MJ_WRITE: + // Invoke the common write routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_WRITE request asynchronously .", 0); + (void)Ext2CommonWrite(PtrIrpContext, PtrIrp ); + break; + + case IRP_MJ_CLEANUP: + // Invoke the common read routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CLEANUP request asynchronously .", 0); + (void)Ext2CommonCleanup(PtrIrpContext, PtrIrp, FALSE); + break; + case IRP_MJ_CLOSE: + // Invoke the common read routine + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CLOSE request asynchronously .", 0); + (void)Ext2CommonClose ( PtrIrpContext, PtrIrp, FALSE ); + break; + + // Continue with the remaining possible dispatch routines below ... + default: + // This is the case where we have an invalid major function + DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing asynchronous request. \nUnable to recoganise the IRP!!! How can this be!!!", 0); + PtrIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + PtrIrp->IoStatus.Information = 0; + + Ext2BreakPoint(); + + IoCompleteRequest(PtrIrp, IO_NO_INCREMENT); + break; + } + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, PtrIrp); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + // Enable preemption + FsRtlExitFileSystem(); + + // Ensure that the "top-level" field is cleared + IoSetTopLevelIrp(NULL); + + PsTerminateSystemThread( RC ); + + + return; +} + +/************************************************************************* +* +* Function: Ext2InitializeVCB() +* +* Description: +* Perform the initialization for a VCB structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2InitializeVCB( +PDEVICE_OBJECT PtrVolumeDeviceObject, +PDEVICE_OBJECT PtrTargetDeviceObject, +PVPB PtrVPB, +PLARGE_INTEGER AllocationSize ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2VCB PtrVCB = NULL; + BOOLEAN VCBResourceInitialized = FALSE; + + PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); + + // Zero it out (typically this has already been done by the I/O + // Manager but it does not hurt to do it again)! + RtlZeroMemory(PtrVCB, sizeof(Ext2VCB)); + + // Initialize the signature fields + PtrVCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_VCB; + PtrVCB->NodeIdentifier.NodeSize = sizeof(Ext2VCB); + + // Initialize the ERESOURCE objects. + RC = ExInitializeResourceLite(&(PtrVCB->VCBResource)); + RC = ExInitializeResourceLite(&(PtrVCB->PagingIoResource)); + + ASSERT(NT_SUCCESS(RC)); + VCBResourceInitialized = TRUE; + + PtrVCB->TargetDeviceObject = PtrTargetDeviceObject; + + PtrVCB->VCBDeviceObject = PtrVolumeDeviceObject; + + PtrVCB->PtrVPB = PtrVPB; + + // Initialize the list anchor (head) for some lists in this VCB. + InitializeListHead(&(PtrVCB->FCBListHead)); + InitializeListHead(&(PtrVCB->NextNotifyIRP)); + InitializeListHead(&(PtrVCB->VolumeOpenListHead)); + InitializeListHead(&(PtrVCB->ClosableFCBs.ClosableFCBListHead)); + PtrVCB->ClosableFCBs.Count = 0; + + // Initialize the notify IRP list mutex + KeInitializeMutex(&(PtrVCB->NotifyIRPMutex), 0); + + // Set the initial file size values appropriately. Note that your FSD may + // wish to guess at the initial amount of information you would like to + // read from the disk until you have really determined that this a valid + // logical volume (on disk) that you wish to mount. + PtrVCB->CommonVCBHeader.AllocationSize.QuadPart = AllocationSize->QuadPart; + + PtrVCB->CommonVCBHeader.FileSize.QuadPart = AllocationSize->QuadPart; + // You typically do not want to bother with valid data length callbacks + // from the Cache Manager for the file stream opened for volume metadata + // information + PtrVCB->CommonVCBHeader.ValidDataLength.LowPart = 0xFFFFFFFF; + PtrVCB->CommonVCBHeader.ValidDataLength.HighPart = 0x7FFFFFFF; + + PtrVCB->CommonVCBHeader.IsFastIoPossible = FastIoIsNotPossible; + + PtrVCB->CommonVCBHeader.Resource = &(PtrVCB->VCBResource); + PtrVCB->CommonVCBHeader.PagingIoResource = &(PtrVCB->PagingIoResource);; + + // Create a stream file object for this volume. + PtrVCB->PtrStreamFileObject = IoCreateStreamFileObject(NULL, + PtrVCB->PtrVPB->RealDevice); + ASSERT(PtrVCB->PtrStreamFileObject); + + // Initialize some important fields in the newly created file object. + PtrVCB->PtrStreamFileObject->FsContext = (void *)(&PtrVCB->CommonVCBHeader); + PtrVCB->PtrStreamFileObject->FsContext2 = NULL; + PtrVCB->PtrStreamFileObject->SectionObjectPointer = &(PtrVCB->SectionObject); + + PtrVCB->PtrStreamFileObject->Vpb = PtrVPB; + PtrVCB->PtrStreamFileObject->ReadAccess = TRUE; + PtrVCB->PtrStreamFileObject->WriteAccess = TRUE; + + // Link this chap onto the global linked list of all VCB structures. + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire Global Resource Exclusively [FileInfo]", 0); + ExAcquireResourceExclusiveLite(&(Ext2GlobalData.GlobalDataResource), TRUE); + InsertTailList(&(Ext2GlobalData.NextVCB), &(PtrVCB->NextVCB)); + DebugTrace(DEBUG_TRACE_MISC, "*** Global Resource Acquired [FileInfo]", 0); + + + + // Initialize caching for the stream file object. + CcInitializeCacheMap(PtrVCB->PtrStreamFileObject, (PCC_FILE_SIZES)(&(PtrVCB->CommonVCBHeader.AllocationSize)), + TRUE, // We will use pinned access. + &(Ext2GlobalData.CacheMgrCallBacks), PtrVCB ); + + + Ext2ReleaseResource(&(Ext2GlobalData.GlobalDataResource)); + DebugTrace(DEBUG_TRACE_MISC, "*** Global Resource Released[FileInfo]", 0); + + // Mark the fact that this VCB structure is initialized. + Ext2SetFlag(PtrVCB->VCBFlags, EXT2_VCB_FLAGS_VCB_INITIALIZED); + PtrVCB->PtrGroupDescriptors = NULL; + PtrVCB->NoOfGroups = 0; + return; +} + + + +/************************************************************************* +* +* Function: Ext2CompleteRequest() +* +* Description: +* This routine completes a Irp. +* +* Expected Interrupt Level (for execution) : +* +* ??? +* +* Arguments: +* +* Irp - Supplies the Irp being processed +* +* Status - Supplies the status to complete the Irp with +* +* Return Value: none +* +*************************************************************************/ +void Ext2CompleteRequest( + IN PIRP Irp OPTIONAL, + IN NTSTATUS Status + ) +{ + // + // If we have an Irp then complete the irp. + // + + if (Irp != NULL) + { + + // + // We got an error, so zero out the information field before + // completing the request if this was an input operation. + // Otherwise IopCompleteRequest will try to copy to the user's buffer. + // + + if ( NT_ERROR(Status) && + FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) { + + Irp->IoStatus.Information = 0; + } + + Irp->IoStatus.Status = Status; + + IoCompleteRequest( Irp, IO_DISK_INCREMENT ); + } + return; +} + + +/************************************************************************* +* +* Function: Ext2CreateNewCCB() +* +* Description: +* We want to create a new CCB. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: A pointer to the CCB structure OR NULL. +* +*************************************************************************/ +NTSTATUS Ext2CreateNewCCB( + PtrExt2CCB *ReturnedCCB, + PtrExt2FCB PtrFCB, + PFILE_OBJECT PtrFileObject ) +{ + PtrExt2CCB PtrCCB; + NTSTATUS RC = STATUS_SUCCESS; + + try + { + + PtrCCB = Ext2AllocateCCB(); + if (!PtrFCB) + { + // Assume lack of memory. + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + PtrCCB->PtrFCB = PtrFCB; + + PtrCCB->PtrFileObject = PtrFileObject; + PtrCCB->CurrentByteOffset.QuadPart = 0; + + if( PtrFCB->ClosableFCBs.OnClosableFCBList ) + { + // This FCB was on the Closable List... + // Taking it off the list... + // + RemoveEntryList( &PtrFCB->ClosableFCBs.ClosableFCBList ); + PtrFCB->ClosableFCBs.OnClosableFCBList = FALSE; + PtrFCB->PtrVCB->ClosableFCBs.Count --; + } + + InterlockedIncrement( &PtrFCB->ReferenceCount ); + InterlockedIncrement( &PtrFCB->OpenHandleCount ); + + InsertTailList( &( PtrFCB->CCBListHead ), &(PtrCCB->NextCCB)); + + *ReturnedCCB = PtrCCB; + try_exit: NOTHING; + } + finally + { + + } + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2DenyAccess() +* +* Description: +* We want to deny access to an IRP +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: NTSTATUS - STATUS_ACCESS_DENIED (always) +* +*************************************************************************/ +NTSTATUS Ext2DenyAccess( IN PIRP Irp ) +{ + ASSERT( Irp ); + + // Just return Access Denied + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_ACCESS_DENIED; + IoCompleteRequest( Irp, IO_DISK_INCREMENT ); + + DebugTrace(DEBUG_TRACE_MISC, "DENYING ACCESS (this will do for now!)...", 0); + + return STATUS_ACCESS_DENIED; +} + + + +/************************************************************************* +* +* Function: Ext2GetFCB_CCB_VCB_FromFileObject() +* +* Description: +* This routine retrieves the FCB, CCB and VCB from the File Object... +* +* Expected Interrupt Level (for execution) : +* +* ? +* +* Return Value: NTSTATUS - STATUS_SUCCESS(always) +* +*************************************************************************/ +NTSTATUS Ext2GetFCB_CCB_VCB_FromFileObject ( + IN PFILE_OBJECT PtrFileObject, + OUT PtrExt2FCB *PPtrFCB, + OUT PtrExt2CCB *PPtrCCB, + OUT PtrExt2VCB *PPtrVCB ) +{ + int Offset; + + (*PPtrCCB) = (PtrExt2CCB)(PtrFileObject->FsContext2); + if( *PPtrCCB ) + { + ASSERT((*PPtrCCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); + (*PPtrFCB) = (*PPtrCCB)->PtrFCB; + + ASSERT((*PPtrFCB)); + + if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) + { + (*PPtrVCB) = (PtrExt2VCB)(*PPtrFCB); + AssertVCB( (*PPtrVCB) ); + + // No FCB + (*PPtrFCB) = NULL; + //found a VCB + } + else + { + AssertFCB( (*PPtrFCB) ); + (*PPtrVCB) = (*PPtrFCB)->PtrVCB; + AssertVCB( (*PPtrVCB) ); + + } + } + else + { + // PtrFileObject->FsContext points to NTRequiredFCB + (*PPtrFCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2FCB, NTRequiredFCB ); + ASSERT((*PPtrFCB)); + //(*PPtrFCB) = PtrFileObject->FsContext; + + if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB) + { + // Making sure I got it right... + AssertFCB( *PPtrFCB ); + (*PPtrVCB) = (*PPtrFCB)->PtrVCB; + AssertVCB( *PPtrVCB ); + } + else + { + // This should be a VCB + + (*PPtrVCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2VCB, CommonVCBHeader ); + AssertVCB( *PPtrVCB ); + + // No FCB + (*PPtrFCB) = NULL; + //found a VCB + } + + } + return STATUS_SUCCESS; +} + + +void Ext2CopyUnicodeString( PUNICODE_STRING PtrDestinationString, PUNICODE_STRING PtrSourceString ) +{ + int Count; + // Allcating space for Destination... + PtrDestinationString->Length = PtrSourceString->Length; + PtrDestinationString->MaximumLength = Ext2QuadAlign( PtrSourceString->Length + 2 ); + PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); + + // RtlCopyUnicodeString( PtrDestinationString, PtrSourceString ); + + for( Count = 0 ; Count < (PtrSourceString->Length/2) ; Count++ ) + { + PtrDestinationString->Buffer[Count] = PtrSourceString->Buffer[Count]; + } + PtrDestinationString->Buffer[Count] = 0; + +} + +void Ext2CopyWideCharToUnicodeString( + PUNICODE_STRING PtrDestinationString, + PCWSTR PtrSourceString ) +{ + + int Count; + + // Determining length... + for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ ); + + // Allcating space for Destination... + PtrDestinationString->Length = Count * 2; + PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 ); + PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); + + // Copying the string over... + for( Count = 0 ; ; Count++ ) + { + PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; + if( PtrSourceString[Count] == 0 ) + break; + } +} + + +void Ext2CopyCharToUnicodeString( + PUNICODE_STRING PtrDestinationString, + PCSTR PtrSourceString, + USHORT SourceStringLength ) +{ + int Count; + // Allcating space for Destination... + PtrDestinationString->Length = SourceStringLength * 2; + PtrDestinationString->MaximumLength = Ext2QuadAlign( SourceStringLength * 2 + 2 ); + PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); + + // Copying the string over... + for( Count = 0 ; Count < SourceStringLength ; Count++ ) + { + PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; + } + PtrDestinationString->Buffer[Count] = 0; + +} + +void Ext2CopyZCharToUnicodeString( PUNICODE_STRING PtrDestinationString, PCSTR PtrSourceString ) +{ + + int Count; + + // Determining length... + for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ ); + + // Allcating space for Destination... + PtrDestinationString->Length = Count * 2; + PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 ); + PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); + + // Copying the string over... + for( Count = 0 ; ; Count++ ) + { + PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; + if( PtrSourceString[Count] == 0 ) + break; + } +} + +void Ext2ZerooutUnicodeString( PUNICODE_STRING PtrUnicodeString ) +{ + PtrUnicodeString->Length = 0; + PtrUnicodeString->MaximumLength =0; + PtrUnicodeString->Buffer = 0; +} + +void Ext2DeallocateUnicodeString( PUNICODE_STRING PtrUnicodeString ) +{ + if( PtrUnicodeString && PtrUnicodeString->Buffer ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrUnicodeString->Buffer ); + ExFreePool( PtrUnicodeString->Buffer ); + } + PtrUnicodeString->Length = 0; + PtrUnicodeString->MaximumLength =0; + PtrUnicodeString->Buffer = 0; +} + +PtrExt2FCB Ext2GetUsedFCB( + PtrExt2VCB PtrVCB ) +{ + + BOOLEAN AllocatedFromZone = FALSE; + PLIST_ENTRY PtrEntry = NULL; + PtrExt2FCB PtrFCB = NULL; + + ASSERT( PtrVCB ); + if( PtrVCB->ClosableFCBs.Count < EXT2_MAXCLOSABLE_FCBS_LL ) + { + // + // Too few Closable FCBs + // Will not reuse any FCBs + // Allocating a new one + // + return Ext2AllocateFCB(); + } + // + // Obtaining a used FCB... + // + + // Retrieving the first entry in the closable FCB list... + + PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead ); + + PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList ); + + // Remembering if the FCB was allocated from the Zone... + AllocatedFromZone = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE ); + + // + // Close this FCB + // + if( !Ext2CloseClosableFCB( PtrFCB ) ) + { + // Couldn't close the FCB!! + // + InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, + &PtrFCB->ClosableFCBs.ClosableFCBList ); + return Ext2AllocateFCB(); + } + + PtrVCB->ClosableFCBs.Count--; + DebugTrace( DEBUG_TRACE_SPECIAL, "Count = %ld [Ext2GetUsedFCB]", PtrVCB->ClosableFCBs.Count ); + + // + // Getting the FCB ready for reuse by + // zeroing it out... + // + RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB))); + + // set up some fields ... + PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB; + PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB)); + + + if (!AllocatedFromZone) + { + Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE); + } + + return PtrFCB; +} + +BOOLEAN Ext2CloseClosableFCB( + PtrExt2FCB PtrFCB) +{ + KIRQL Irql = 0; + PFILE_OBJECT PtrFileObject = NULL; + + AssertFCB( PtrFCB ); + + // Attempting to acquire the FCB Exclusively... + if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) + { + Ext2BreakPoint(); + return FALSE; + } + + Irql = KeGetCurrentIrql( ); + + if( PtrFCB->ReferenceCount ) + { + // How the hell can this happen!!! + Ext2BreakPoint(); + } + if( PtrFCB->OpenHandleCount ) + { + // How the hell can this happen!!! + Ext2BreakPoint(); + } + + // Deleting entry from VCB's FCB list... + RemoveEntryList( &PtrFCB->NextFCB ); + + PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; + + PtrFileObject = PtrFCB->DcbFcb.Dcb.PtrDirFileObject; + + if ( PtrFileObject ) + { + // + // Clear the Cache Map... + // + if( PtrFileObject->PrivateCacheMap != NULL) + { + IO_STATUS_BLOCK Status; + DebugTrace( DEBUG_TRACE_SPECIAL, ">>.........Flushing cache.........<<", 0 ); + CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status ); + CcUninitializeCacheMap( PtrFileObject, NULL, NULL ); + } + // + // The File Object is no longer required... + // Close it by dereferenceing it!!! + // + PtrFileObject->FsContext = NULL; + PtrFileObject->FsContext2 = NULL; + ObDereferenceObject( PtrFileObject ); + + PtrFCB->DcbFcb.Dcb.PtrDirFileObject = NULL; + PtrFileObject = NULL; + } + + // Uninitialize the Resources... + ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource ); + ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource ); + + // + // Releasing the FCB Name Object... + // + if( PtrFCB->FCBName ) + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name %S", PtrFCB->FCBName->ObjectName.Buffer ); + Ext2ReleaseObjectName( PtrFCB->FCBName ); + } + else + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name *Unknown*", 0 ); + } + return TRUE; +} + + +BOOLEAN Ext2SaveBCB( + PtrExt2IrpContext PtrIrpContext, + PBCB PtrBCB, + PFILE_OBJECT PtrFileObject) +{ + PEXT2_SAVED_BCBS PtrSavedBCB; + PLIST_ENTRY PtrEntry = NULL; + + if( !PtrIrpContext ) + { + // + // NULL passed instead of the IRP Context + // This call should be ignored... + // + return TRUE; + } + + if( !AssertBCB( PtrBCB ) ) + { + DebugTrace( DEBUG_TRACE_MISC, "Not saving BCB!!! [Ext2SaveBCB]", 0 ); + return FALSE; + } + + + DebugTrace( DEBUG_TRACE_SPECIAL, "Saving BCB [Ext2SaveBCB]", 0 ); + + // Has the BCB been saved already? + for( PtrEntry = PtrIrpContext->SavedBCBsListHead.Flink; + PtrEntry != &PtrIrpContext->SavedBCBsListHead; + PtrEntry = PtrEntry->Flink ) + { + PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry ); + ASSERT( PtrSavedBCB ); + if( PtrSavedBCB->PtrBCB == PtrBCB ) + { + + // A BCB for this file has already been saved for flushing... + // Won't resave this one... + return TRUE; + } + } + + + // Reference the BCB + CcRepinBcb( PtrBCB ); + + // Now allocate a EXT2_SAVED_BCBS + PtrSavedBCB = Ext2AllocatePool( NonPagedPool, + Ext2QuadAlign( sizeof( EXT2_SAVED_BCBS ) ) ); + if( !PtrSavedBCB ) + return FALSE; + PtrSavedBCB->NodeIdentifier.NodeSize = sizeof( EXT2_SAVED_BCBS ); + PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_SAVED_BCB; + + PtrSavedBCB->PtrBCB = PtrBCB; + // PtrSavedBCB->PtrFileObject = PtrFileObject; + + // Now save it in the IRP Context + InsertHeadList( &PtrIrpContext->SavedBCBsListHead, &PtrSavedBCB->SavedBCBsListEntry ); + + PtrIrpContext->SavedCount++; + // Return success... + return TRUE; + +} + + +BOOLEAN Ext2FlushSavedBCBs( + PtrExt2IrpContext PtrIrpContext ) +{ + + PLIST_ENTRY PtrEntry = NULL; + PEXT2_SAVED_BCBS PtrSavedBCB = NULL; + IO_STATUS_BLOCK Status; + BOOLEAN RC = TRUE; + + if( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) ) + { + DebugTrace( DEBUG_TRACE_SPECIAL, "Flushing cache... - Ext2FlushSavedBCBs", 0 ); + } + while( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) ) + { + + PtrEntry = RemoveTailList( &PtrIrpContext->SavedBCBsListHead ); + if( !PtrEntry ) + { + // No more entries left... + break; + } + + // Get the Saved BCB + PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry ); + if( PtrSavedBCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_SAVED_BCB ) + { + // Something is wrong... + Ext2BreakPoint(); + return FALSE; + } + + if( !AssertBCB( PtrSavedBCB->PtrBCB ) ) + { + // This BCB shouldn't have been saved in the first place... + DebugTrace( DEBUG_TRACE_ERROR, "Unable to flush BCB - Skipping!!! [Ext2SaveBCB]", 0 ); + continue; + } + + // Unpin and Flush the cache... + CcUnpinRepinnedBcb( PtrSavedBCB->PtrBCB, TRUE, &Status ); + + if( !NT_SUCCESS( Status.Status ) ) + { + // Failure in flushing... + DebugTrace( DEBUG_TRACE_SPECIAL, "Failure flushing cache - Ext2FlushSavedBCBs", 0 ); + RC = FALSE; + } + + // Release the Saved BCB + PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_INVALID; + + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrSavedBCB ); + ExFreePool( PtrSavedBCB ); + PtrSavedBCB = NULL; + PtrIrpContext->SavedCount--; + } + + return RC; +} + +BOOLEAN AssertBCB( PBCB PtrBCB ) +{ + PFILE_OBJECT PtrFileObject = NULL; + + /* + * This routine is simplified version of the original + * AssertBCB and doesn't make any assumptions about + * the layout of undocumented BCB structure. + * -- Filip Navara, 18/08/2004 + */ + + PtrFileObject = CcGetFileObjectFromBcb ( PtrBCB ); + if( !PtrFileObject ) + { + Ext2BreakPoint(); + return FALSE; + } + else + { + return TRUE; + } + } + + +ULONG Ext2Align( ULONG NumberToBeAligned, ULONG Alignment ) +{ + if( Alignment & ( Alignment - 1 ) ) + { + // + // Alignment not a power of 2 + // Just returning + // + return NumberToBeAligned; + } + if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 ) + { + NumberToBeAligned = NumberToBeAligned + Alignment; + NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) ); + } + return NumberToBeAligned; +} + +LONGLONG Ext2Align64( LONGLONG NumberToBeAligned, LONGLONG Alignment ) +{ + if( Alignment & ( Alignment - 1 ) ) + { + // + // Alignment not a power of 2 + // Just returning + // + return NumberToBeAligned; + } + if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 ) + { + NumberToBeAligned = NumberToBeAligned + Alignment; + NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) ); + } + return NumberToBeAligned; +} + + +ULONG Ext2GetCurrentTime() +{ + LARGE_INTEGER CurrentTime; + ULONG Time; + KeQuerySystemTime( &CurrentTime ); + Time = (ULONG) ( (CurrentTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); + return Time; +} diff --git a/reactos/drivers/filesystems/ext2/src/read.c b/reactos/drivers/filesystems/ext2/src/read.c new file mode 100644 index 00000000000..e4b47de045c --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/read.c @@ -0,0 +1,1476 @@ +/************************************************************************* +* +* File: read.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Read" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_READ + +#define DEBUG_LEVEL (DEBUG_TRACE_READ) + + +/************************************************************************* +* +* Function: Ext2Read() +* +* Description: +* The I/O Manager will invoke this routine to handle a read +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2Read( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Read IRP Received...", 0); + + // Ext2BreakPoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonRead(PtrIrpContext, Irp, TRUE); + + } + except ( Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation() ) ) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2CommonRead() +* +* Description: +* The actual work is performed here. This routine may be invoked in one +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonRead( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp, +BOOLEAN FirstAttempt ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + LARGE_INTEGER ByteOffset; + uint32 ReadLength = 0, TruncatedReadLength = 0; + uint32 NumberBytesRead = 0; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PERESOURCE PtrResourceAcquired = NULL; + IO_STATUS_BLOCK LocalIoStatus; + PVOID PtrSystemBuffer = NULL; + PVOID PtrPinnedReadBuffer = NULL; + uint32 KeyValue = 0; + + BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + + BOOLEAN CanWait = FALSE; + BOOLEAN PagingIo = FALSE; + BOOLEAN NonBufferedIo = FALSE; + BOOLEAN SynchronousIo = FALSE; + BOOLEAN MdlLocked = FALSE; + BOOLEAN ReadTruncated = FALSE; + + LARGE_INTEGER StartPhysicalBlock; + ULONG NoOfBlocks = 0; + + PIO_STACK_LOCATION PtrIrpNextSp = NULL; + + // Used to cache the Single Indirect blocks pointed to by + // the Double Indirect block + PEXT2_SIBLOCKS PtrDIArray = NULL; + ULONG DIArrayCount = 0; + + // Used to cache the Single Indirect blocks pointed to by + // the Triple Indirect block + PEXT2_SIBLOCKS PtrTIArray = NULL; + ULONG TIArrayCount = 0; + + EXT2_IO_RUN * PtrIoRuns = NULL; + + ULONG Start; + ULONG End; + ULONG LogicalBlockIndex; + ULONG BytesRemaining; + ULONG BytesReadSoFar; + ULONG LeftOver; + ULONG LogicalBlockSize; + ULONG PhysicalBlockSize; + + PBCB PtrPinnedSIndirectBCB = NULL; + PBCB PtrPinnedDIndirectBCB = NULL; + PBCB PtrPinnedTIndirectBCB = NULL; + + int i, Index; + + try + { + try{ + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + // If this happens to be a MDL read complete request, then + // there is not much processing that the FSD has to do. + if (PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE) + { + // Caller wants to tell the Cache Manager that a previously + // allocated MDL can be freed. + Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, TRUE); + // The IRP has been completed. + CompleteIrp = FALSE; + try_return(RC = STATUS_SUCCESS); + } + + // If this is a request at IRQL DISPATCH_LEVEL, then post + // the request (your FSD may choose to process it synchronously + // if you implement the support correctly; obviously you will be + // quite constrained in what you can do at such IRQL). + if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC) + { + DebugTrace(DEBUG_TRACE_MISC, " === Deferring Read ", 0 ); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Get the FCB and CCB pointers + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + // Get some of the parameters supplied to us + ByteOffset = PtrIoStackLocation->Parameters.Read.ByteOffset; + ReadLength = PtrIoStackLocation->Parameters.Read.Length; + + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE); + NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE); + SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE); + + if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Read File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); + } + else + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Read File Name : -null-", 0); + } + + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->ByteCount = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length); + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->ByteOffset.LowPart = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart); + + if( CanWait ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->Can Wait ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->Can't Wait ", 0 ); + } + + if( PagingIo ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->Paging Io ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->Not Paging Io", 0 ); + } + + if( SynchronousIo ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->SynchronousIo ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->ASynchronousIo ", 0 ); + } + + if( NonBufferedIo ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->NonBufferedIo", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, " ->BufferedIo", 0 ); + } + + + if (ReadLength == 0) + { + // a 0 byte read can be immediately succeeded + try_return(RC); + } + + // Is this a read of the volume itself ? + if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) + { + // + // >>>>>>>>>>> Volume Read <<<<<<<<<<<< + // + // Yep, we need to send this on to the disk driver after + // validation of the offset and length. + + // PtrVCB = (PtrExt2VCB)(PtrFCB); + + if (PtrVCB->VCBFlags & EXT2_FCB_PAGE_FILE ) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, "[Read] *Volume Page File *", 0); + } + + // Acquire the volume resource shared ... + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Read]", PtrFileObject); + } + + if( PagingIo ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Shared [Read]", 0); + DebugTraceState( "VCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [Read]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrVCB->PagingIoResource), FALSE )) + { + // post the request to be processed in the context of a worker thread + DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Acquisition FAILED [Read]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Acquired [Read]", 0); + + PtrResourceAcquired = &(PtrVCB->PagingIoResource); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Shared [Read]", 0); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Read]", PtrVCB->VCBResource.ActiveCount, + PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrVCB->VCBResource), FALSE )) + { + // post the request to be processed in the context of a worker thread + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [Read]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired [Read]", 0); + + PtrResourceAcquired = &(PtrVCB->VCBResource); + } + if( !PagingIo ) + { + if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart ) + { + RC = STATUS_END_OF_FILE; + NumberBytesRead = 0; + try_return( RC ); + } + } + if( PagingIo || NonBufferedIo ) + { + DebugTrace(DEBUG_TRACE_MISC, "[Volume Read] PagingIo or NonBufferedIo ", 0); + CompleteIrp = FALSE; + + RC = Ext2PassDownSingleReadWriteIRP ( + PtrIrpContext, PtrIrp, PtrVCB, + ByteOffset, ReadLength, SynchronousIo); + + try_return(RC); + } + else + { + // Buffer Control Block + PBCB PtrBCB = NULL; + DebugTrace(DEBUG_TRACE_READ_DETAILS, "[Volume Read] BufferedIo ", 0); + // + // Let the cache manager worry about this read... + // Pinned access should have been initiated. + // But checking anyway... + // + ASSERT( PtrVCB->PtrStreamFileObject ); + ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &ByteOffset, + ReadLength, + TRUE, + &PtrBCB, + &PtrPinnedReadBuffer) ) + { + + RC = STATUS_UNSUCCESSFUL; + NumberBytesRead = 0; + try_return( RC ); + } + else + { + PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp); + RtlCopyBytes( PtrSystemBuffer, PtrPinnedReadBuffer, ReadLength ); + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + RC = STATUS_SUCCESS; + NumberBytesRead = ReadLength; + try_return(RC); + + } + } + } + + + // If the read request is directed to a page file + // send the request directly to the disk driver. + // For requests directed to a page file, you have to trust + // that the offsets will be set correctly by the VMM. You should not + // attempt to acquire any FSD resources either. + + if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE) + { + IoMarkIrpPending(PtrIrp); + // You will need to set a completion routine before invoking + // a lower level driver + // forward request directly to disk driver + // Ext2PageFileIo(PtrIrpContext, PtrIrp); + DebugTrace( DEBUG_TRACE_SPECIAL, "[Read] To a *Page File* - Not handled \ngoing into a hang...", 0); + CompleteIrp = FALSE; + try_return(RC = STATUS_PENDING); + } + + + // + // If this read is directed to a directory... + // Paging IO is allowed though... + // + if ( ( PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY ) && !PagingIo ) + { + RC = STATUS_INVALID_DEVICE_REQUEST; + try_return(RC); + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // Check whether the desired read can be allowed depending + // on any byte range locks that might exist. Note that for + // paging-io, no such checks should be performed. + if (!PagingIo) + { + // Insert code to perform the check here ... + // + // if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp, PtrCurrentIoStackLocation)) + // { + // try_return(RC = STATUS_FILE_LOCK_CONFLICT); + // } + } + + // There are certain complications that arise when the same file stream + // has been opened for cached and non-cached access. The FSD is then + // responsible for maintaining a consistent view of the data seen by + // the caller. + // Also, it is possible for file streams to be mapped in both as data files + // and as an executable. This could also lead to consistency problems since + // there now exist two separate sections (and pages) containing file + // information. + // Read Chapter 10 for more information on the issues involved in + // maintaining data consistency. + // The test below flushes the data cached in system memory if the current + // request madates non-cached access (file stream must be cached) and + // (a) the current request is not paging-io which indicates it is not + // a recursive I/O operation OR originating in the Cache Manager + // (b) OR the current request is paging-io BUT it did not originate via + // the Cache Manager (or is a recursive I/O operation) and we do + // have an image section that has been initialized. + + + + #define EXT2_REQ_NOT_VIA_CACHE_MGR(ptr) (!MmIsRecursiveIoFault() && ((ptr)->ImageSectionObject != NULL)) + + if( NonBufferedIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL) ) + { + if (!PagingIo || (EXT2_REQ_NOT_VIA_CACHE_MGR(&(PtrReqdFCB->SectionObject)))) + { + CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, ReadLength, &(PtrIrp->IoStatus)); + // If the flush failed, return error to the caller + if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status)) + { + try_return(RC); + } + } + } + + // + // Synchronizing with other reads and writes... + // Acquire the appropriate FCB resource shared + // + if ( PagingIo ) + { + // Try to acquire the FCB PagingIoResource shared + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Read]", PtrFileObject); + } + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCBPaging Shared [Read]", 0); + DebugTraceState( "FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [Read]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->PagingIoResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Acquisition FAILED [Read]", 0); + + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Acquired [Read]", 0); + + // Remember the resource that was acquired + PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource); + } + else + { + // Try to acquire the FCB MainResource shared + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Read]", PtrFileObject); + } + DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared [Read]", 0); + DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Read]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); + if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Read]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquired [Read]", 0); + + // Remember the resource that was acquired + PtrResourceAcquired = &(PtrReqdFCB->MainResource); + } + + // Read in the File inode... + Ext2InitializeFCBInodeInfo( PtrFCB ); + + if (!PagingIo) + { + LARGE_INTEGER CurrentTime; + KeQuerySystemTime( &CurrentTime ); + PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart; + } + + // Validate start offset and length supplied. + if (ByteOffset.QuadPart >= PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) + { + // Starting offset is > file size + try_return(RC = STATUS_END_OF_FILE); + } + + /* + * Round down the size of Paging I/O requests too. I'm not + * sure if the FS driver is responsible for doing that, but + * all other drivers I have seen do it. + * -- Filip Navara, 18/08/2004 + */ + if ( ByteOffset.QuadPart + ReadLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) + { + // Read going beyond the end of file... + // Adjusting the Read Length... + ReadLength = (UINT)(PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart - ByteOffset.QuadPart); + if (PagingIo) + ReadLength = ROUND_TO_PAGES(ReadLength); + ReadTruncated = TRUE; + } + + // This is also a good place to set whether fast-io can be performed + // on this particular file or not. Your FSD must make it's own + // determination on whether or not to allow fast-io operations. + // Commonly, fast-io is not allowed if any byte range locks exist + // on the file or if oplocks prevent fast-io. Practically any reason + // choosen by your FSD could result in your setting FastIoIsNotPossible + // OR FastIoIsQuestionable instead of FastIoIsPossible. + // + // PtrReqdFCB->CommonFCBHeader.IsFastIoPossible = FastIoIsPossible; + + + // Branch here for cached vs non-cached I/O + + if (!NonBufferedIo) + { + DebugTrace(DEBUG_TRACE_READ_DETAILS, "[File Read] BufferedIo ", 0); + + // The caller wishes to perform cached I/O. Initiate caching if + // this is the first cached I/O operation using this file object + if (PtrFileObject->PrivateCacheMap == NULL) + { + // This is the first cached I/O operation. You must ensure + // that the FCB Common FCB Header contains valid sizes at this time + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), + FALSE, // We will not utilize pin access for this file + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrCCB); // The context used in callbacks + } + + // Check and see if this request requires a MDL returned to the caller + if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL) + { + // Caller does want a MDL returned. Note that this mode + // implies that the caller is prepared to block + CcMdlRead(PtrFileObject, &ByteOffset, TruncatedReadLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus)); + NumberBytesRead = PtrIrp->IoStatus.Information; + RC = PtrIrp->IoStatus.Status; + + try_return(RC); + } + + // This is a regular run-of-the-mill cached I/O request. Let the + // Cache Manager worry about it! + // First though, we need a buffer pointer (address) that is valid + PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp); + ASSERT(PtrSystemBuffer); + + if (!CcCopyRead(PtrFileObject, &(ByteOffset), ReadLength, CanWait, PtrSystemBuffer, &(PtrIrp->IoStatus))) + { + // The caller was not prepared to block and data is not immediately + // available in the system cache + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure. Cannot read without blocking...", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + } + + // We have the data + RC = PtrIrp->IoStatus.Status; + NumberBytesRead = PtrIrp->IoStatus.Information; + try_return(RC); + } + else // NonBuffered or Paged IO + { + LONGLONG SingleIndirectBlockSize ; + LONGLONG DoubleIndirectBlockSize ; + LONGLONG TripleIndirectBlockSize ; + LONGLONG DirectBlockSize ; + + LONGLONG NoOfDirectBlocks ; + LONGLONG NoOfSingleIndirectBlocks ; + LONGLONG NoOfDoubleIndirectBlocks ; + LONGLONG NoOfTripleIndirectBlocks ; + + ULONG * PtrPinnedSIndirectBlock = NULL; + ULONG * PtrPinnedDIndirectBlock = NULL; + ULONG * PtrPinnedTIndirectBlock = NULL; + + // Used when reading a Triple Indirect Block... + LONGLONG FirstCachedDIBlockOffset = 0; + + // Used when reading a Double Indirect Block... + LONGLONG FirstCachedSIBlockOffset = 0; + + DebugTrace(DEBUG_TRACE_MISC, "[File Read] Paging IO or NonBufferedIo ", 0); + + // Calculating where the read should start from... + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize; + + NoOfDirectBlocks = EXT2_NDIR_BLOCKS ; + NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG ); + NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + + DirectBlockSize = LogicalBlockSize * NoOfDirectBlocks; + SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks; + DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ; + TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks; + + LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize); + + /* + if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Handle Triple indirect blocks? + // A Pop up will do for now... + // + UNICODE_STRING ErrorMessage; + Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" ); + DebugTrace(DEBUG_TRACE_ERROR, "@@@@@@@@ Triple indirect blocks need to be read in! \n@@@@@@@@ This is not supported as yet!", 0); + IoRaiseInformationalHardError( + IO_ERR_DRIVER_ERROR, + &ErrorMessage, + KeGetCurrentThread( ) ); + + Ext2DeallocateUnicodeString( &ErrorMessage ); + + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + + } + */ + if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize && + ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) ) + { + // + // Single Indirect Blocks required... + // Read in the single indirect blocks... + // + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Single Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the single indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedSIndirectBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + } + if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize && + ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Double Indirect Blocks required... + // Read in the double indirect blocks... + // + + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the double indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedDIndirectBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // So far so good... + // Now determine the single indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + } + else + { + StartIndirectBlock = 0; + } + + FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks; + + if( ByteOffset.QuadPart + ReadLength >= + DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + ReadLength - + (DirectBlockSize + SingleIndirectBlockSize); + } + EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; + EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; + + DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock); + + PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + { + ULONG i; + + for( i = 0; i < DIArrayCount; i++ ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrDIArray[i].PtrBCB, + (PVOID*)&PtrDIArray[i].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + } + } + } + + if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Triple Indirect Blocks required... + // Read in the triple indirect blocks... + // + LONGLONG StartTIndirectBlock; + LONGLONG EndTIndirectBlock; + + LONGLONG StartDIndirectBlock; + LONGLONG EndDIndirectBlock; + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + LONGLONG ByteOffsetTillHere = 0; + + PBCB TempDIBCB; + LONG* TempDIBuffer; + + ULONG TIArrayIndex = 0; + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Triple Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize; + + DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffset = 0x%I64X", ByteOffset ); + DebugTrace(DEBUG_TRACE_TRIPLE, "ReadLength = 0x%lX", ReadLength ); + DebugTrace(DEBUG_TRACE_TRIPLE, "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ); + // + // Asking the cache manager to oblige by pinning the triple indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedTIndirectBCB, + (PVOID*)&PtrPinnedTIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // Determine the no of BCBs that need to be saved... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + StartTIndirectBlock = ByteOffset.QuadPart; + } + else + { + StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; + } + EndTIndirectBlock = ByteOffset.QuadPart + ReadLength; + TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2; + + + PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + + // Now determine the double indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); + StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize; + StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks; + + ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ; + //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize; + FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; + } + else + { + ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; + FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; + StartDIndirectBlock = 0; + } + + DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere ); + + EndDIndirectBlock = ByteOffset.QuadPart + ReadLength - + (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); + EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ; + EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks; + + { + // Reading in the necessary double indirect bocks... + ULONG i; + LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock; + + for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize) + { + VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize; + + DebugTrace(DEBUG_TRACE_TRIPLE, "Double VolOffset = 0x%I64X", VolumeByteOffset ); + + if( !CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &TempDIBCB, + (PVOID*)&TempDIBuffer) ) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + try_return(RC = STATUS_PENDING); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + if( ByteOffset.QuadPart > ByteOffsetTillHere) + { + StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + + if( TIArrayIndex == 0 ) + { + FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks; + } + } + else + { + StartIndirectBlock = 0; + } + + if( ByteOffset.QuadPart + ReadLength >= ByteOffsetTillHere + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + ReadLength - ByteOffsetTillHere; + } + EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; + EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; + + { + ULONG i; + + for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ ) + { + VolumeByteOffset.QuadPart = TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize; + DebugTrace(DEBUG_TRACE_TRIPLE, "Single VolOffset = 0x%I64X", VolumeByteOffset ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrTIArray[ TIArrayIndex ].PtrBCB, + (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + TIArrayIndex++; + } + } + CcUnpinData( TempDIBCB ); + TempDIBCB = NULL; + TempDIBuffer = NULL; + } + } + TIArrayCount = TIArrayIndex; + + DebugTrace(DEBUG_TRACE_TRIPLE, "TIArrayCount = %ld", TIArrayCount ); + DebugTrace(DEBUG_TRACE_TRIPLE, "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset ); + } + + + // + // Allocating memory for IO Runs + // + Index = ( (ReadLength - 2) / LogicalBlockSize + 2 ); + PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) ) ); + + + Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) ); + BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart ); + + if( ReadLength > BytesRemaining ) + { + End = Start + BytesRemaining; + } + else + { + End = Start + ReadLength; + } + BytesReadSoFar = 0; + + Index = 0; + DebugTrace(DEBUG_TRACE_MISC, "\nDetermining the read IRPs that have to be passed down...", 0); + + while( 1 ) + { + BytesReadSoFar += (End-Start); + if( LogicalBlockIndex < NoOfDirectBlocks ) + { + // Direct Block + PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ]; + } + else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) + { + // Single Indirect Block + PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - NoOfDirectBlocks ]; + } + else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) + { + LONGLONG BlockNo; + LONGLONG IBlockIndex; + LONGLONG BlockIndex; + + BlockNo = LogicalBlockIndex - FirstCachedSIBlockOffset; + IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; + BlockIndex = BlockNo % NoOfSingleIndirectBlocks; + + // Double Indirect Block + PtrIoRuns[ Index ].LogicalBlock = + PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ]; + } + else + { + // Triple Indirect Block + LONGLONG BlockNo; + LONGLONG IBlockIndex; + LONGLONG BlockIndex; + BlockNo = LogicalBlockIndex - FirstCachedDIBlockOffset; + IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; + BlockIndex = BlockNo % NoOfSingleIndirectBlocks; + + DbgPrint( "\nBlock No : 0x%I64X IBlockIndex = 0x%I64X BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex); + + if( IBlockIndex >= TIArrayCount ) + { + Ext2BreakPoint(); + } + if( BlockIndex >= LogicalBlockSize ) + { + Ext2BreakPoint(); + } + + PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];; + DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock ); + } + + if( PtrIoRuns[ Index ].LogicalBlock == 0 ) + { + // + // Something is wrong... + // + //Ext2BreakPoint(); + Index--; + break; + + } + + + PtrIoRuns[ Index ].StartOffset = Start; + PtrIoRuns[ Index ].EndOffset = End; + PtrIoRuns[ Index ].PtrAssociatedIrp = NULL; + + DebugTrace( DEBUG_TRACE_MISC, " Index = (%ld)", LogicalBlockIndex ); + DebugTrace( DEBUG_TRACE_MISC, " Logical Block = (0x%lX)", PtrIoRuns[ Index ].LogicalBlock ); + DebugTrace( DEBUG_TRACE_MISC, " Start = (0x%lX)", Start ); + DebugTrace( DEBUG_TRACE_MISC, " End = (0x%lX) ", End ); + DebugTrace( DEBUG_TRACE_MISC, " Bytes read (0x%lX)", BytesReadSoFar ); + + + + if( BytesReadSoFar >= ReadLength ) + break; + LogicalBlockIndex++; + Start = 0; + LeftOver = ReadLength - BytesReadSoFar; + if( LeftOver > LogicalBlockSize ) + End = LogicalBlockSize; + else + End = LeftOver; + // Loop over to make the read request... + Index++; + } + // + // Unpin the Indirect Blocks + // + if( PtrPinnedSIndirectBCB ) + { + CcUnpinData( PtrPinnedSIndirectBCB ); + PtrPinnedSIndirectBCB = NULL; + PtrPinnedSIndirectBlock = NULL; + } + + if( PtrPinnedDIndirectBCB ) + { + CcUnpinData( PtrPinnedDIndirectBCB ); + PtrPinnedDIndirectBCB = NULL; + PtrPinnedDIndirectBlock = NULL; + } + + if( PtrPinnedTIndirectBCB) + { + CcUnpinData( PtrPinnedTIndirectBCB); + PtrPinnedTIndirectBCB = NULL; + PtrPinnedTIndirectBlock = NULL; + } + + if ( PtrDIArray ) + { + ULONG i; + for( i = 0; i < DIArrayCount; i++ ) + { + CcUnpinData( PtrDIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrDIArray ); + ExFreePool( PtrDIArray ); + PtrDIArray = NULL; + } + if ( PtrTIArray ) + { + ULONG i; + for( i = 0; i < TIArrayCount; i++ ) + { + CcUnpinData( PtrTIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrTIArray ); + ExFreePool( PtrTIArray ); + PtrTIArray = NULL; + } + // + // Pass down Associated IRPs to the Target Device Driver... + // + DebugTrace( DEBUG_TRACE_MISC, "Passing down the Read IRPs to the disk driver...", 0 ); + + RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, ReadLength, PtrIrpContext, PtrFCB, SynchronousIo ); + + // + // Irp will be completed automatically + // when all the Associated IRPs are completed + // + if( RC == STATUS_SUCCESS || RC == STATUS_PENDING ) + { + CompleteIrp = FALSE; + } + try_return( RC ); + + } + try_exit: NOTHING; + } + except (EXCEPTION_EXECUTE_HANDLER) + { + DebugTrace(DEBUG_TRACE_ERROR, "@@@@@@@@ Exception Handler", 0); + } + } + finally + { + if ( PtrIoRuns ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrIoRuns ); + ExFreePool( PtrIoRuns ); + } + // + // Unpin the Indirect Blocks + // + if( PtrPinnedSIndirectBCB ) + { + CcUnpinData( PtrPinnedSIndirectBCB ); + PtrPinnedSIndirectBCB = NULL; + } + + if( PtrPinnedDIndirectBCB ) + { + CcUnpinData( PtrPinnedDIndirectBCB ); + PtrPinnedDIndirectBCB = NULL; + } + if( PtrPinnedTIndirectBCB ) + { + CcUnpinData( PtrPinnedTIndirectBCB ); + PtrPinnedTIndirectBCB = NULL; + } + + if ( PtrDIArray ) + { + ULONG i; + for( i = 0; i < DIArrayCount; i++ ) + { + CcUnpinData( PtrDIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrDIArray ); + ExFreePool( PtrDIArray ); + } + + if ( PtrTIArray ) + { + ULONG i; + for( i = 0; i < TIArrayCount; i++ ) + { + CcUnpinData( PtrTIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrTIArray ); + ExFreePool( PtrTIArray ); + } + + // Release any resources acquired here ... + if (PtrResourceAcquired) + { + Ext2ReleaseResource(PtrResourceAcquired); + + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Read]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Read]", PtrFileObject); + } + if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Read]", 0); + } + else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Released [Read]", 0); + } + else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Paging Resource Released [Read]", 0); + } + else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Resource Released [Read]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Unknown Resource Released [Read]", 0); + } + + PtrResourceAcquired = NULL; + } + + // Post IRP if required + if ( PostRequest ) + { + + // Implement a routine that will queue up the request to be executed + // later (asynchronously) in the context of a system worker thread. + // See Chapter 10 for details. + + // Lock the callers buffer here. Then invoke a common routine to + // perform the post operation. + if (!(PtrIoStackLocation->MinorFunction & IRP_MN_MDL)) + { + RC = Ext2LockCallersBuffer(PtrIrp, TRUE, ReadLength); + ASSERT(NT_SUCCESS(RC)); + } + + // Perform the post operation which will mark the IRP pending + // and will return STATUS_PENDING back to us + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + else if (CompleteIrp && !(RC == STATUS_PENDING)) + { + // For synchronous I/O, the FSD must maintain the current byte offset + // Do not do this however, if I/O is marked as paging-io + if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) + { + PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset, RtlConvertUlongToLargeInteger((unsigned long)NumberBytesRead)); + } + + // If the read completed successfully and this was not a paging-io + // operation, set a flag in the CCB that indicates that a read was + // performed and that the file time should be updated at cleanup + if (NT_SUCCESS(RC) && !PagingIo) + { + Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_ACCESSED); + } + + // Can complete the IRP here if no exception was encountered + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) + { + + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = NumberBytesRead; + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + } // can we complete the IRP ? + else + { + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + } + } // end of "finally" processing + + return(RC); +} + + + + +/************************************************************************* +* +* Function: Ext2GetCallersBuffer() +* +* Description: +* Obtain a pointer to the caller's buffer. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +void * Ext2GetCallersBuffer ( + PIRP PtrIrp ) +{ + void * ReturnedBuffer = NULL; + + // If an MDL is supplied, use it. + if (PtrIrp->MdlAddress) + { + ReturnedBuffer = MmGetSystemAddressForMdl(PtrIrp->MdlAddress); + } + else + { + ReturnedBuffer = PtrIrp->UserBuffer; + } + + return (ReturnedBuffer); +} + + + +/************************************************************************* +* +* Function: Ext2LockCallersBuffer() +* +* Description: +* Obtain a MDL that describes the buffer. Lock pages for I/O +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2LockCallersBuffer( +PIRP PtrIrp, +BOOLEAN IsReadOperation, +uint32 Length) +{ + NTSTATUS RC = STATUS_SUCCESS; + PMDL PtrMdl = NULL; + + ASSERT(PtrIrp); + + try + { + // Is a MDL already present in the IRP + if( !(PtrIrp->MdlAddress) ) + { + // Allocate a MDL + if (!(PtrMdl = IoAllocateMdl(PtrIrp->UserBuffer, Length, FALSE, FALSE, PtrIrp))) + { + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return(RC); + } + + // Probe and lock the pages described by the MDL + // We could encounter an exception doing so, swallow the exception + // NOTE: The exception could be due to an unexpected (from our + // perspective), invalidation of the virtual addresses that comprise + // the passed in buffer + try + { + MmProbeAndLockPages(PtrMdl, PtrIrp->RequestorMode, (IsReadOperation ? IoWriteAccess:IoReadAccess)); + } + except(EXCEPTION_EXECUTE_HANDLER) + { + RC = STATUS_INVALID_USER_BUFFER; + } + } + + try_exit: NOTHING; + + } + finally + { + if (!NT_SUCCESS(RC) && PtrMdl) + { + IoFreeMdl(PtrMdl); + // You MUST NULL out the MdlAddress field in the IRP after freeing + // the MDL, else the I/O Manager will also attempt to free the MDL + // pointed to by that field during I/O completion. Obviously, the + // pointer becomes invalid once you free the allocated MDL and hence + // you will encounter a system crash during IRP completion. + PtrIrp->MdlAddress = NULL; + } + } + + return(RC); +} + + + +/************************************************************************* +* +* Function: Ext2MdlComplete() +* +* Description: +* Tell Cache Manager to release MDL (and possibly flush). +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None. +* +*************************************************************************/ +void Ext2MdlComplete( + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp, + PIO_STACK_LOCATION PtrIoStackLocation, + BOOLEAN ReadCompletion) +{ + + NTSTATUS RC = STATUS_SUCCESS; + PFILE_OBJECT PtrFileObject = NULL; + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // Not much to do here. + if( ReadCompletion ) + { + CcMdlReadComplete( PtrFileObject, PtrIrp->MdlAddress ); + } + else + { + // The Cache Manager needs the byte offset in the I/O stack location. + CcMdlWriteComplete( PtrFileObject, &(PtrIoStackLocation->Parameters.Write.ByteOffset), PtrIrp->MdlAddress ); + } + + // Clear the MDL address field in the IRP so the IoCompleteRequest() + // does not try to play around with the MDL. + PtrIrp->MdlAddress = NULL; + + // Free up the Irp Context. + Ext2ReleaseIrpContext(PtrIrpContext); + + // Complete the IRP. + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = 0; + IoCompleteRequest(PtrIrp, IO_NO_INCREMENT); + + return; +} diff --git a/reactos/drivers/filesystems/ext2/src/shutdown.c b/reactos/drivers/filesystems/ext2/src/shutdown.c new file mode 100644 index 00000000000..0ec7d2f36b8 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/shutdown.c @@ -0,0 +1,211 @@ +/************************************************************************* +* +* File: shutdown.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "shutdown notification" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_SHUTDOWN +#define DEBUG_LEVEL (DEBUG_TRACE_SHUTDOWN) + + +/************************************************************************* +* +* Function: Ext2Shutdown() +* +* Description: +* All disk-based FSDs can expect to receive this shutdown notification +* request whenever the system is about to be halted gracefully. If you +* design and implement a network redirector, you must register explicitly +* for shutdown notification by invoking the IoRegisterShutdownNotification() +* routine from your driver entry. +* +* Note that drivers that register to receive shutdown notification get +* invoked BEFORE disk-based FSDs are told about the shutdown notification. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant. +* +*************************************************************************/ +NTSTATUS Ext2Shutdown( + PDEVICE_OBJECT DeviceObject, // the logical volume device object + PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Shutdown IRP received...", 0); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonShutdown(PtrIrpContext, Irp); + + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonShutdown() +* +* Description: +* The actual work is performed here. Basically, all we do here is +* internally invoke a flush on all mounted logical volumes. This, in +* tuen, will result in all open file streams being flushed to disk. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: Irrelevant +* +*************************************************************************/ +NTSTATUS Ext2CommonShutdown( +PtrExt2IrpContext PtrIrpContext, +PIRP PtrIrp) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + IO_STATUS_BLOCK LocalIoStatus; + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + // (a) Block all new "mount volume" requests by acquiring an appropriate + // global resource/lock. + // (b) Go through your linked list of mounted logical volumes and for + // each such volume, do the following: + // (i) acquire the volume resource exclusively + // (ii) invoke Ext2FlushLogicalVolume() (internally) to flush the + // open data streams belonging to the volume from the system + // cache + // (iii) Invoke the physical/virtual/logical target device object + // on which the volume is mounted and inform this device + // about the shutdown request (Use IoBuildSynchronousFsdRequest() + // to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you + // will then issue to the target device object). + // (iv) Wait for the completion of the shutdown processing by the target + // device object + // (v) Release the VCB resource you will have acquired in (i) above. + + // Once you have processed all the mounted logical volumes, you can release + // all acquired global resources and leave (in peace :-) + + + +/*//////////////////////////////////////////// + // + // Update the Group... + // + if( PtrVCB->LogBlockSize ) + { + // First block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize; + } + else + { + // Second block contains the descriptors... + VolumeByteOffset.QuadPart = LogicalBlockSize * 2; + } + + NumberOfBytesToRead = sizeof( struct ext2_group_desc ); + NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrBCB, + &PtrCacheBuffer )) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); + } + else + { + // + // Saving up Often Used Group Descriptor Information in the VCB... + // + unsigned int DescIndex ; + + DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); + PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer; + for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ ) + { + PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock + = PtrGroupDescriptor[ DescIndex ].bg_inode_table; + + PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock + = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap + ; + PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock + = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap + ; + PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount + = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count; + + PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount + = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count; + } + CcUnpinData( PtrBCB ); + PtrBCB = NULL; + } +*///////////////////////////////////////////// + + try_exit: NOTHING; + + } + finally + { + + // See the read/write examples for how to fill in this portion + + } // end of "finally" processing + + return(RC); +} diff --git a/reactos/drivers/filesystems/ext2/src/volinfo.c b/reactos/drivers/filesystems/ext2/src/volinfo.c new file mode 100644 index 00000000000..2e341626e03 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/volinfo.c @@ -0,0 +1,339 @@ +/************************************************************************* +* +* File: volinfo.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the various Volume Information related calls. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + + + +#include "ext2fsd.h" + + + + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_VOL_INFORMATION +#define DEBUG_LEVEL (DEBUG_TRACE_VOLINFO) + + +/************************************************************************* +* +* Function: Ext2QueryVolInfo() +* +* Description: +* The I/O Manager will invoke this routine to handle a +* Query Volume Info IRP +* +* Expected Interrupt Level (for execution) : +* +* ??? +* +* Arguments: +* +* DeviceObject - Supplies the volume device object where the +* file exists +* +* Irp - Supplies the Irp being processed +* +* +* Return Value: +* +* NTSTATUS - The FSD status for the IRP +* +*************************************************************************/ +NTSTATUS Ext2QueryVolInfo ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + // The Return Status + NTSTATUS Status = STATUS_SUCCESS; + + // The IRP Stack Location + PIO_STACK_LOCATION IrpSp = NULL; + + // Volume Control Block + PtrExt2VCB PtrVCB = NULL; + + // The class of the query IRP + FS_INFORMATION_CLASS FsInformationClass; + + // The System Buffer Pointer + PVOID Buffer = NULL; + + // Parameter Length + ULONG Length = 0; + + // Bytes copied... + ULONG BytesCopied = 0; + + // Pointers to the Output Information... + PFILE_FS_VOLUME_INFORMATION PtrVolumeInformation = NULL; + PFILE_FS_SIZE_INFORMATION PtrSizeInformation = NULL; + PFILE_FS_ATTRIBUTE_INFORMATION PtrAttributeInformation = NULL; + PFILE_FS_DEVICE_INFORMATION PtrDeviceInformation = NULL; + PFILE_FS_FULL_SIZE_INFORMATION PtrFullSizeInformation = NULL; + + + // Now for the handler code... + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "QueryVolumeInformation IRP", 0); + + FsRtlEnterFileSystem(); + + try + { + // Getting a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT( IrpSp ); + + // Getting the VCB and Verifying it... + PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension ); + ASSERT(PtrVCB); + ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); + + // Getting the query parameters... + Length = IrpSp->Parameters.QueryVolume.Length; + FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass; + Buffer = Irp->AssociatedIrp.SystemBuffer; + + // Now servicing the request depending on the type... + switch (FsInformationClass) + { + case FileFsVolumeInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsVolumeInformation", 0); + PtrVolumeInformation = Buffer; + PtrVolumeInformation->SupportsObjects = FALSE; + PtrVolumeInformation->VolumeCreationTime.QuadPart = 0; + RtlCopyMemory( + PtrVolumeInformation->VolumeLabel, // destination + PtrVCB->PtrVPB->VolumeLabel, // source + PtrVCB->PtrVPB->VolumeLabelLength ); + PtrVolumeInformation->VolumeLabelLength = PtrVCB->PtrVPB->VolumeLabelLength; + PtrVolumeInformation->VolumeSerialNumber = PtrVCB->PtrVPB->SerialNumber; + BytesCopied = sizeof( FILE_FS_VOLUME_INFORMATION ) + PtrVolumeInformation->VolumeLabelLength - sizeof( WCHAR); + break; + + case FileFsSizeInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsSizeInformation", 0); + PtrSizeInformation = Buffer; + PtrSizeInformation->BytesPerSector = DeviceObject->SectorSize; + PtrSizeInformation->AvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount; + PtrSizeInformation->SectorsPerAllocationUnit = ( EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize; + PtrSizeInformation->TotalAllocationUnits.QuadPart = PtrVCB->BlocksCount; + BytesCopied = sizeof( FILE_FS_SIZE_INFORMATION ); + break; + + case FileFsDeviceInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsDeviceInformation", 0); + PtrDeviceInformation = Buffer; + PtrDeviceInformation->DeviceType = FILE_DEVICE_DISK; + PtrDeviceInformation->Characteristics = FILE_DEVICE_IS_MOUNTED; + BytesCopied = sizeof( FILE_FS_DEVICE_INFORMATION ); + break; + + case FileFsAttributeInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsAttributeInformation", 0); + PtrAttributeInformation = Buffer; + RtlCopyMemory( PtrAttributeInformation->FileSystemName, L"EXT2", 10 ); + PtrAttributeInformation->FileSystemNameLength = 8; + PtrAttributeInformation->MaximumComponentNameLength = 255; + PtrAttributeInformation->FileSystemAttributes = + FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; + BytesCopied = sizeof( FILE_FS_ATTRIBUTE_INFORMATION ) + 8; + + break; + + case FileFsFullSizeInformation: + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsFullSizeInformation", 0); + PtrFullSizeInformation = Buffer; + PtrFullSizeInformation->BytesPerSector = DeviceObject->SectorSize; + PtrFullSizeInformation->ActualAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount; + PtrFullSizeInformation->SectorsPerAllocationUnit = (EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize; + PtrFullSizeInformation->TotalAllocationUnits.QuadPart = PtrVCB->BlocksCount; + PtrFullSizeInformation->CallerAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount - PtrVCB->ReservedBlocksCount; + BytesCopied = sizeof( FILE_FS_FULL_SIZE_INFORMATION ); + break; + + default: + Status = STATUS_INVALID_PARAMETER; + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - STATUS_INVALID_PARAMETER", 0); + break; + } + + if( IrpSp->Parameters.QueryVolume.Length < BytesCopied ) + { + BytesCopied = IrpSp->Parameters.QueryVolume.Length; + Status = STATUS_BUFFER_OVERFLOW; + DebugTrace(DEBUG_TRACE_MISC, " === Buffer insufficient", 0); + } + try_exit: NOTHING; + } + finally + { + Irp->IoStatus.Information = BytesCopied; + Ext2CompleteRequest( Irp, Status ); + } + FsRtlExitFileSystem(); + + // + // Now return to the caller + // + + return Status; +} + + + +NTSTATUS Ext2SetVolInfo( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + // The Return Status + NTSTATUS Status = STATUS_SUCCESS; + + // The IRP Stack Location + PIO_STACK_LOCATION IrpSp = NULL; + + // Volume Control Block + PtrExt2VCB PtrVCB = NULL; + + // The class of the query IRP + FS_INFORMATION_CLASS FsInformationClass; + + // Pointers to the Output Information... + PFILE_FS_LABEL_INFORMATION PtrVolumeLabelInformation = NULL; + + // Now for the handler code... + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Set Volume Information IRP", 0); + + FsRtlEnterFileSystem(); + + try + { + // Getting a pointer to the current I/O stack location + IrpSp = IoGetCurrentIrpStackLocation(Irp); + ASSERT( IrpSp ); + + // Getting the VCB and Verifying it... + PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension ); + AssertVCB(PtrVCB); + + // Getting the query parameters... + // Length = IrpSp->Parameters.SetVolume.Length; +#ifdef _GNU_NTIFS_ + FsInformationClass = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.SetVolume.FsInformationClass; +#else + FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass; +#endif + + // Now servicing the request depending on the type... + switch (FsInformationClass) + { + case FileFsLabelInformation: + PtrVolumeLabelInformation = Irp->AssociatedIrp.SystemBuffer; + if( PtrVolumeLabelInformation->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH || // This is the maximum that the + // VPB can take... + PtrVolumeLabelInformation->VolumeLabelLength > 32 ) // this is the maximum that Ext2 FS can support.. + { + try_return( Status = STATUS_INVALID_VOLUME_LABEL ); + } + + PtrVCB->PtrVPB->VolumeLabelLength = (USHORT)PtrVolumeLabelInformation->VolumeLabelLength ; + RtlCopyMemory( + PtrVCB->PtrVPB->VolumeLabel, // destination + PtrVolumeLabelInformation->VolumeLabel, // source + PtrVolumeLabelInformation->VolumeLabelLength ); + + { + // Now update the volume's super block... + + PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; + PBCB PtrSuperBlockBCB = NULL; + LARGE_INTEGER VolumeByteOffset; + ULONG LogicalBlockSize = 0; + ULONG NumberOfBytesToRead = 0; + + + // Reading in the super block... + VolumeByteOffset.QuadPart = 1024; + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + // THis shouldn't be more than a block in size... + NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); + + if( !CcPinRead( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + NumberOfBytesToRead, + TRUE, + &PtrSuperBlockBCB, + (PVOID*)&PtrSuperBlock ) ) + { + DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); + try_return( Status = STATUS_INVALID_VOLUME_LABEL ); + } + else + { + ULONG i; + for( i = 0; i < (PtrVolumeLabelInformation->VolumeLabelLength/2) ; i++ ) + { + PtrSuperBlock->s_volume_name[i] = + (char) PtrVolumeLabelInformation->VolumeLabel[i] ; + if( PtrSuperBlock->s_volume_name[i] == 0 ) + { + break; + } + } + if( i < 16 ) + { + PtrSuperBlock->s_volume_name[i] = 0; + } + + + CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); + + // Not saving and flushing this information synchronously... + // This is not a critical information.. + // Settling for lazy writing of this information + + // Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); + + if( PtrSuperBlockBCB ) + { + CcUnpinData( PtrSuperBlockBCB ); + PtrSuperBlockBCB = NULL; + } + + } + } + + break; + default: + Status = STATUS_INVALID_PARAMETER; + DebugTrace(DEBUG_TRACE_MISC, "Query Volume - STATUS_INVALID_PARAMETER", 0); + break; + } + + try_exit: NOTHING; + } + finally + { + Irp->IoStatus.Information = 0; + Ext2CompleteRequest( Irp, Status ); + } + FsRtlExitFileSystem(); + + // + // Now return to the caller + // + + return Status; +} diff --git a/reactos/drivers/filesystems/ext2/src/write.c b/reactos/drivers/filesystems/ext2/src/write.c new file mode 100644 index 00000000000..1596ecd95eb --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/write.c @@ -0,0 +1,1483 @@ +/************************************************************************* +* +* File: write.c +* +* Module: Ext2 File System Driver (Kernel mode execution only) +* +* Description: +* Contains code to handle the "Write" dispatch entry point. +* +* Author: Manoj Paul Joseph +* +* +*************************************************************************/ + +#include "ext2fsd.h" + +// define the file specific bug-check id +#define EXT2_BUG_CHECK_ID EXT2_FILE_WRITE + +#define DEBUG_LEVEL (DEBUG_TRACE_WRITE) + + +/************************************************************************* +* +* Function: Ext2Write() +* +* Description: +* The I/O Manager will invoke this routine to handle a write +* request +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution +* to be deferred to a worker thread context) +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2Write( +PDEVICE_OBJECT DeviceObject, // the logical volume device object +PIRP Irp) // I/O Request Packet +{ + NTSTATUS RC = STATUS_SUCCESS; + PtrExt2IrpContext PtrIrpContext = NULL; + BOOLEAN AreWeTopLevel = FALSE; + + DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Write IRP Received...", 0); + + // Ext2BreakPoint(); + + FsRtlEnterFileSystem(); + ASSERT(DeviceObject); + ASSERT(Irp); + + // set the top level context + AreWeTopLevel = Ext2IsIrpTopLevel(Irp); + + try + { + // get an IRP context structure and issue the request + PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); + ASSERT(PtrIrpContext); + + RC = Ext2CommonWrite(PtrIrpContext, Irp); + } + except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) + { + RC = Ext2ExceptionHandler(PtrIrpContext, Irp); + Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); + } + + if (AreWeTopLevel) + { + IoSetTopLevelIrp(NULL); + } + + FsRtlExitFileSystem(); + + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2CommonWrite() +* +* Description: +* The actual work is performed here. This routine may be invoked in one' +* of the two possible contexts: +* (a) in the context of a system worker thread +* (b) in the context of the original caller +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS Ext2CommonWrite( + PtrExt2IrpContext PtrIrpContext, + PIRP PtrIrp) +{ + + NTSTATUS RC = STATUS_SUCCESS; + PIO_STACK_LOCATION PtrIoStackLocation = NULL; + LARGE_INTEGER ByteOffset; + uint32 WriteLength = 0; + uint32 NumberBytesWritten = 0; + PFILE_OBJECT PtrFileObject = NULL; + PtrExt2FCB PtrFCB = NULL; + PtrExt2CCB PtrCCB = NULL; + PtrExt2VCB PtrVCB = NULL; + PtrExt2NTRequiredFCB PtrReqdFCB = NULL; + PERESOURCE PtrResourceAcquired = NULL; + IO_STATUS_BLOCK LocalIoStatus; + void *PtrSystemBuffer = NULL; + uint32 KeyValue = 0; + + BOOLEAN CompleteIrp = TRUE; + BOOLEAN PostRequest = FALSE; + + BOOLEAN CanWait = FALSE; + BOOLEAN PagingIo = FALSE; + BOOLEAN NonBufferedIo = FALSE; + BOOLEAN SynchronousIo = FALSE; + BOOLEAN IsThisADeferredWrite = FALSE; + BOOLEAN WritingAtEndOfFile = FALSE; + + EXT2_IO_RUN *PtrIoRuns = NULL; + + PBCB PtrPinnedSIndirectBCB = NULL; + PBCB PtrPinnedDIndirectBCB = NULL; + PBCB PtrPinnedTIndirectBCB = NULL; + + // Used to cache the Single Indirect blocks pointed to by + // the Double Indirect block + PEXT2_SIBLOCKS PtrDIArray = NULL; + ULONG DIArrayCount = 0; + + // Used to cache the Single Indirect blocks pointed to by + // the Triple Indirect block + PEXT2_SIBLOCKS PtrTIArray = NULL; + ULONG TIArrayCount = 0; + + + try + { + // First, get a pointer to the current I/O stack location + PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); + ASSERT(PtrIoStackLocation); + + PtrFileObject = PtrIoStackLocation->FileObject; + ASSERT(PtrFileObject); + + // If this happens to be a MDL write complete request, then + // allocated MDL can be freed. + if(PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE) + { + // Caller wants to tell the Cache Manager that a previously + // allocated MDL can be freed. + Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, FALSE); + // The IRP has been completed. + CompleteIrp = FALSE; + try_return(RC = STATUS_SUCCESS); + } + + // If this is a request at IRQL DISPATCH_LEVEL, then post the request + if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + + // Get the FCB and CCB pointers + Ext2GetFCB_CCB_VCB_FromFileObject ( + PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); + + + // Get some of the parameters supplied to us + ByteOffset = PtrIoStackLocation->Parameters.Write.ByteOffset; + WriteLength = PtrIoStackLocation->Parameters.Write.Length; + + CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); + PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE); + NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE); + SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE); + + if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Write File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); + } + else + { + DebugTrace(DEBUG_TRACE_FILE_NAME, " === Write File Name : -null-", 0); + } + + DebugTrace( DEBUG_TRACE_SPECIAL, " ->ByteCount = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length); + DebugTrace( DEBUG_TRACE_SPECIAL, " ->ByteOffset.LowPart = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart); + + if( CanWait ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Can Wait ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Can't Wait ", 0 ); + } + + if( PagingIo ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Paging Io ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Not Paging Io", 0 ); + } + + if( SynchronousIo ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->SynchronousIo ", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->ASynchronousIo ", 0 ); + } + + if( NonBufferedIo ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->NonBufferedIo", 0 ); + } + else + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->BufferedIo", 0 ); + } + // Check at this point whether the file object being + // used for write really did have write permission requested when the + // create/open operation was performed. + // Don't do this for paging io... + + if (WriteLength == 0) + { + // a 0 byte write can be immediately succeeded + try_return(RC); + } + + // Is this a write of the volume itself ? + if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) + { + // + // >>>>>>>>>>>>>>>>>> VOLUME WRITE <<<<<<<<<<<<<< + // + + // Validate the offset and length first... + // ....................................... + + // Acquire the volume resource exclusively + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Write]", PtrFileObject); + } + + if( PagingIo ) + { + // This is Paging IO... + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCBPaging Exclusively [Write]", 0); + DebugTraceState( "VCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [Write]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters ); + + if( !ExAcquireResourceExclusiveLite( &( PtrVCB->PagingIoResource ), FALSE ) ) + { + // post the request to be processed in the context of a worker thread + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCBPaging Acquisition FAILED [Write]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCBPaging Acquired [Write]", 0); + PtrResourceAcquired = &(PtrVCB->PagingIoResource); + } + else + { + // This is not Paging IO... + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Write]", 0); + DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Write]", PtrVCB->VCBResource.ActiveCount, + PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); + + if( !ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) + { + // post the request to be processed in the context of a worker thread + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Write]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired [Write]", 0); + PtrResourceAcquired = &(PtrVCB->VCBResource); + } + + // Validate the caller supplied offset here + if( !PagingIo ) + { + if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart ) + { + // Write extending beyond the end of volume. + // Deny access... + // + RC = STATUS_END_OF_FILE; + NumberBytesWritten = 0; + try_return( RC ); + } + } + + // Lock the callers buffer + if (!NT_SUCCESS(RC = Ext2LockCallersBuffer(PtrIrp, TRUE, WriteLength))) + { + try_return(RC); + } + + // Forward the request to the lower level driver + if( PagingIo || NonBufferedIo ) + { + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "[Volume Write] PagingIo or NonBufferedIo ", 0); + CompleteIrp = FALSE; + + // + // Do the write operation... + // Send down the IRP to the lower level driver... + // + // Returned Informations and Status will be set by the lower level driver... + // The IRP will also be completed by the lower level driver... + + RC = Ext2PassDownSingleReadWriteIRP ( + PtrIrpContext, PtrIrp, PtrVCB, + ByteOffset, WriteLength, SynchronousIo ); + + try_return(RC); + } + else + { + PBCB PtrBCB = NULL; + PVOID PtrBuffer = NULL; + + DebugTrace(DEBUG_TRACE_READ_DETAILS, "[Volume Write] BufferedIo ", 0); + // + // Let the cache manager worry about this write... + // Pinned access should have been initiated. + // But checking anyway... + // + ASSERT( PtrVCB->PtrStreamFileObject ); + ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap ); + + CcPreparePinWrite( + PtrVCB->PtrStreamFileObject, + &ByteOffset, + WriteLength, + FALSE, // Don't Zero... + TRUE, // Can Wait... + &PtrBCB, + &PtrBuffer); + + // Do the write now... + // Write to the Pinned buffer... + // Cache Manager will do the disk write... + RtlCopyBytes( PtrBuffer, PtrSystemBuffer, WriteLength ); + // CcSetDirtyPinnedData( PtrBCB, NULL ); + CcUnpinData( PtrBCB ); + PtrBuffer = NULL; + PtrBCB = NULL; + + NumberBytesWritten = WriteLength; + + // Go ahead and complete the IRP... + } + try_return(RC); + } + + + IsThisADeferredWrite = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_DEFERRED_WRITE) ? TRUE : FALSE); + + if (!NonBufferedIo) + { + /**************************************************************************** + if (!CcCanIWrite(PtrFileObject, WriteLength, CanWait, IsThisADeferredWrite)) + { + // Cache Manager and/or the VMM does not want us to perform + // the write at this time. Post the request. + Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_DEFERRED_WRITE); + CcDeferWrite( PtrFileObject, Ext2DeferredWriteCallBack, PtrIrpContext, PtrIrp, WriteLength, IsThisADeferredWrite); + CompleteIrp = FALSE; + try_return( RC = STATUS_PENDING ); + } + ****************************************************************************/ + } + + // If the write request is directed to a page file + // send the request directly to the disk + // driver. For requests directed to a page file, you have to trust + // that the offsets will be set correctly by the VMM. You should not + // attempt to acquire any FSD resources either. + if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE) + { + IoMarkIrpPending(PtrIrp); + + // You will need to set a completion routine before invoking a lower level driver. + // Forward request directly to disk driver. + // Ext2PageFileIo(PtrIrpContext, PtrIrp); + + CompleteIrp = FALSE; + + try_return(RC = STATUS_PENDING); + } + + // Check whether this write operation is targeted + // to a directory object... + + if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY) + { + // + // Is this a write a result of + // cached directory manipulation operatio + // by the FSD itself? + // + if( PagingIo ) + { + // Yep! Allow it to proceed... + } + else + { + // Nope... User initiated directory writes are not allowed! + // Fail this request... + RC = STATUS_INVALID_DEVICE_REQUEST; + try_return(RC); + } + } + + PtrReqdFCB = &(PtrFCB->NTRequiredFCB); + + // + // Synchronizing with other reads and writes... + // Acquire the appropriate FCB resource exclusively + // + if (PagingIo) + { + // Try to acquire the FCB PagingIoResource exclusively + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCBpaging Exclusively [Write]", 0); + + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCBpaging Acquisition FAILED [Write]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + // Remember the resource that was acquired + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCBpaging Acquired [Write]", 0); + PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource); + } + else + { + // Try to acquire the FCB MainResource exclusively + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Write]", 0); + if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait)) + { + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Write]", 0); + CompleteIrp = FALSE; + PostRequest = TRUE; + try_return(RC = STATUS_PENDING); + } + // Remember the resource that was acquired + DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquired [Write]", 0); + PtrResourceAcquired = &(PtrReqdFCB->MainResource); + } + + // Validate start offset and length supplied. + // Here is a special check that determines whether the caller wishes to + // begin the write at current end-of-file (whatever the value of that + // offset might be) + if ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == 0xFFFFFFFF)) + { + WritingAtEndOfFile = TRUE; + ByteOffset.QuadPart = PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart; + } + + // + // If this is a Non Cached io and if caching has been initiated, + // Flush and purge the cache + // + if (NonBufferedIo && !PagingIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL)) + { + // Flush and then attempt to purge the cache + CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, WriteLength, &(PtrIrp->IoStatus)); + // If the flush failed, return error to the caller + if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status)) + { + try_return(RC); + } + + // Attempt the purge and ignore the return code + CcPurgeCacheSection( &(PtrReqdFCB->SectionObject), (WritingAtEndOfFile ? &(PtrReqdFCB->CommonFCBHeader.FileSize) : &(ByteOffset)), + WriteLength, FALSE); + // We are finished with our flushing and purging + } + + if (!PagingIo) + { + // Insert code to perform the check here ... + // + // if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp, + // PtrCurrentIoStackLocation)) + // { + // try_return(RC = STATUS_FILE_LOCK_CONFLICT); + // } + } + + // Read in the File inode... + Ext2InitializeFCBInodeInfo( PtrFCB ); + + if (!PagingIo) + { + LARGE_INTEGER CurrentTime; + KeQuerySystemTime( &CurrentTime ); + PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart; + PtrFCB->LastWriteTime.QuadPart = CurrentTime.QuadPart; + } + + { + // + // Validate start offset and length supplied. + // + ULONG LogicalBlockSize = 0; + LONGLONG NoOfNewBlocksRequired = 0; + LONGLONG NoOfBytesRequired = 0; + LONGLONG i; + BOOLEAN ZeroOut = FALSE; + LARGE_INTEGER StartOffsetForZeroing; + LARGE_INTEGER EndOffsetForZeroing; + + + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + + if ( ByteOffset.QuadPart + WriteLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) + { + if( PagingIo ) + { + // + // A paging request never modifies the file size... + // + if( ByteOffset.QuadPart + >= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) + { + // Page request for writing outside the file... + // No op this IRP by completing it... + // + try_return(RC); + } + if( ByteOffset.QuadPart + WriteLength + > PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) + { + // Page request for writing outside the file alocation size... + // Truncate the write size so that it is within the allocation limit... + // + WriteLength = (ULONG) (PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart - ByteOffset.QuadPart); + } + } + else + { + + // Starting offset is > file size + // Allocate new blocks? + NoOfBytesRequired = ByteOffset.QuadPart + WriteLength + - PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart; + + if( NoOfBytesRequired ) + { + NoOfNewBlocksRequired = Ext2Align64( NoOfBytesRequired, LogicalBlockSize ) + / LogicalBlockSize; + for( i = 0; i < NoOfNewBlocksRequired ; i++ ) + { + Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE ); + } + + ZeroOut = TRUE; + + if( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart < ByteOffset.QuadPart ) + { + // Curr EOF --> | | <--New EOF + // ----------------------------------------------- + // | | |///////////| | + // | File Contents | Free |// Write //| Free | <- End of Allocation + // | | |///////////| | + // ----------------------------------------------- + // | | + + // Write is beyond the current end of file... + // This will create a hole... + // Will have to zero this out... + + // Start offset is the Current File size + StartOffsetForZeroing = PtrReqdFCB->CommonFCBHeader.FileSize; + // End offset is the point at which this write is going to start + EndOffsetForZeroing = ByteOffset; + } + else + { + // Curr EOF --> | | <--New EOF + // ------------------------------------------ + // | |///////////////| | + // | File Contents |//// Write ////| Free | <- End of Allocation + // | |///////////////| | + // ------------------------------------------ + // | | + + // Just zero out the end of the file + // not covered by the file size + + // Start offset is the New File size + StartOffsetForZeroing.QuadPart = + ByteOffset.QuadPart + WriteLength; + // End offset is the New Allocation size + EndOffsetForZeroing.QuadPart = PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart; + } + } + + PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart = + ByteOffset.QuadPart + WriteLength; + + ASSERT( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart <= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ); + + Ext2UpdateFileSize( PtrIrpContext, PtrFileObject, PtrFCB ); + + try + { + // + // Zero the blocks out... + // This routine can be used even if caching has not been initiated... + // + if( ZeroOut == TRUE && StartOffsetForZeroing.QuadPart != EndOffsetForZeroing.QuadPart ) + { + CcZeroData( PtrFileObject, + &StartOffsetForZeroing, + &EndOffsetForZeroing, + FALSE ); + + if( EndOffsetForZeroing.QuadPart != PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) + { + // Also zero out the file tip... + CcZeroData( PtrFileObject, + &PtrReqdFCB->CommonFCBHeader.FileSize, + &PtrReqdFCB->CommonFCBHeader.AllocationSize, + FALSE ); + } + } + } + finally + { + // Swallow an exceptions that are raised... + } + } + } + } + + // + // Branch here for cached vs non-cached I/O + // + if (!NonBufferedIo) + { + + // The caller wishes to perform cached I/O. + // Initiate caching if it hasn't been done already... + if (PtrFileObject->PrivateCacheMap == NULL) + { + CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), + FALSE, // We will not utilize pin access for this file + &(Ext2GlobalData.CacheMgrCallBacks), // callbacks + PtrCCB); // The context used in callbacks + } + + // Check and see if this request requires a MDL returned to the caller + if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL) + { + // Caller does want a MDL returned. Note that this mode + // implies that the caller is prepared to block + CcPrepareMdlWrite(PtrFileObject, &ByteOffset, WriteLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus)); + NumberBytesWritten = PtrIrp->IoStatus.Information; + RC = PtrIrp->IoStatus.Status; + + try_return(RC); + } + + // This is a regular run-of-the-mill cached I/O request. Let the + // Cache Manager worry about it! + + // First though, we need a buffer pointer (address) that is valid + PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp); + ASSERT(PtrSystemBuffer); + if ( !CcCopyWrite(PtrFileObject, &(ByteOffset), WriteLength, CanWait, PtrSystemBuffer)) + { + // The caller was not prepared to block and data is not immediately + // available in the system cache + CompleteIrp = FALSE; + PostRequest = TRUE; + // Mark Irp Pending ... + try_return(RC = STATUS_PENDING); + } + else + { + // We have the data + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = NumberBytesWritten = WriteLength; + } + } + else // NonBuffered or Paged IO + { + + ULONG Start = 0; + ULONG End = 0; + ULONG LogicalBlockIndex = 0; + ULONG BytesRemaining = 0; + ULONG BytesWrittenSoFar = 0; + ULONG LeftOver = 0; + ULONG LogicalBlockSize = 0; + ULONG PhysicalBlockSize = 0; + ULONG Index = 0; + + LONGLONG SingleIndirectBlockSize = 0; + LONGLONG DoubleIndirectBlockSize = 0; + LONGLONG TripleIndirectBlockSize = 0; + LONGLONG DirectBlockSize = 0; + + LONGLONG NoOfDirectBlocks ; + LONGLONG NoOfSingleIndirectBlocks ; + LONGLONG NoOfDoubleIndirectBlocks ; + LONGLONG NoOfTripleIndirectBlocks ; + + ULONG * PtrPinnedSIndirectBlock = NULL; + ULONG * PtrPinnedDIndirectBlock = NULL; + ULONG * PtrPinnedTIndirectBlock = NULL; + + // Used when reading a Triple Indirect Block... + LONGLONG FirstCachedDIBlockOffset = 0; + + // Used when reading a Double Indirect Block... + LONGLONG FirstCachedSIBlockOffset = 0; + + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "[File Write] Paging IO or NonBufferedIo ", 0); + + // Calculating where the write should start from... + LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; + PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize; + + NoOfDirectBlocks = EXT2_NDIR_BLOCKS ; + NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG ); + NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); + + DirectBlockSize = LogicalBlockSize * NoOfDirectBlocks; + SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks; + DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ; + TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks; + + LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize); + + if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Handle Triple indirect blocks? + // A Pop up will do for now... + // + UNICODE_STRING ErrorMessage; + Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" ); + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "@@@@@@@@ Triple indirect blocks need to be written to! \n@@@@@@@@ This is not supported as yet!", 0); + /* REACTOS FIXME */ + IoRaiseInformationalHardError( + /* IO_ERR_DRIVER_ERROR */(NTSTATUS)0xC0040004L, + &ErrorMessage, + KeGetCurrentThread( ) ); + + Ext2DeallocateUnicodeString( &ErrorMessage ); + RC = STATUS_INSUFFICIENT_RESOURCES; + try_return ( RC ); + } + + if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize && + ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) ) + { + LARGE_INTEGER VolumeByteOffset; + + // + // Indirect Blocks required... + // Read in the single indirect blocks... + // + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "Reading in some Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_NDIR_BLOCKS ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the single indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedSIndirectBCB, + (PVOID*)&PtrPinnedSIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data", 0); + } + } + if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize && + ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Double Indirect Blocks required... + // Read in the double indirect blocks... + // + + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the double indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedDIndirectBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // So far so good... + // Now determine the single indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + } + else + { + StartIndirectBlock = 0; + } + + FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks; + + if( ByteOffset.QuadPart + WriteLength >= + DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + WriteLength - + (DirectBlockSize + SingleIndirectBlockSize); + } + EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; + EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; + + DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock); + + PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + { + ULONG i; + + for( i = 0; i < DIArrayCount; i++ ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrDIArray[i].PtrBCB, + (PVOID*)&PtrDIArray[i].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + } + } + } + +/* { + // + // Double Indirect Blocks required... + // Read in the double indirect blocks... + // + + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; + + // + // Asking the cache manager to oblige by pinning the double indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedDIndirectBCB, + (PVOID*)&PtrPinnedDIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // So far so good... + // Now determine the single indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + } + else + { + StartIndirectBlock = 0; + } + + if( ByteOffset.QuadPart + WriteLength >= + DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + WriteLength - + (DirectBlockSize + SingleIndirectBlockSize); + if( EndIndirectBlock % LogicalBlockSize ) + { + EndIndirectBlock += LogicalBlockSize; + } + EndIndirectBlock = EndIndirectBlock / LogicalBlockSize; + if( EndIndirectBlock % NoOfSingleIndirectBlocks) + { + EndIndirectBlock += NoOfSingleIndirectBlocks; + } + EndIndirectBlock = EndIndirectBlock / NoOfSingleIndirectBlocks; + } + DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock); + PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + { + ULONG i; + + for( i = 0; i < DIArrayCount; i++ ) + { + VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize; + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrDIArray[i].PtrBCB, + (PVOID*)&PtrDIArray[i].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + } + } + } +*/ + if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // + // Triple Indirect Blocks required... + // Read in the triple indirect blocks... + // + LONGLONG StartTIndirectBlock; + LONGLONG EndTIndirectBlock; + + LONGLONG StartDIndirectBlock; + LONGLONG EndDIndirectBlock; + LONGLONG StartIndirectBlock; + LONGLONG EndIndirectBlock; + + LONGLONG ByteOffsetTillHere = 0; + + PBCB TempDIBCB; + LONG* TempDIBuffer; + + ULONG TIArrayIndex = 0; + + LARGE_INTEGER VolumeByteOffset; + + DebugTrace(DEBUG_TRACE_MISC, "Reading in some Triple Indirect Blocks", 0); + + VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize; + + DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffset = 0x%I64X", ByteOffset ); + DebugTrace(DEBUG_TRACE_TRIPLE, "WriteLength = 0x%lX", WriteLength ); + DebugTrace(DEBUG_TRACE_TRIPLE, "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ); + // + // Asking the cache manager to oblige by pinning the triple indirect block... + // + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrPinnedTIndirectBCB, + (PVOID*)&PtrPinnedTIndirectBlock )) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + + // Mark Irp Pending ... + IoMarkIrpPending( PtrIrp ); + RC = STATUS_PENDING; + try_return(RC); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + // Determine the no of BCBs that need to be saved... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + StartTIndirectBlock = ByteOffset.QuadPart; + } + else + { + StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; + } + EndTIndirectBlock = ByteOffset.QuadPart + WriteLength; + TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2; + + + PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); + + // Now determine the double indirect blocks that will have to be read in... + if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) + { + // Request doesnot require any single indirect or direct blocks + StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); + StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize; + StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks; + + ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ; + //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize; + FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; + } + else + { + ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; + FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; + StartDIndirectBlock = 0; + } + + DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere ); + + EndDIndirectBlock = ByteOffset.QuadPart + WriteLength - + (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); + EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ; + EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks; + + { + // Reading in the necessary double indirect bocks... + ULONG i; + LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock; + + for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize) + { + VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize; + + DebugTrace(DEBUG_TRACE_TRIPLE, "Double VolOffset = 0x%I64X", VolumeByteOffset ); + + if( !CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &TempDIBCB, + (PVOID*)&TempDIBuffer) ) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + try_return(RC = STATUS_PENDING); + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + + if( ByteOffset.QuadPart > ByteOffsetTillHere) + { + StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere); + StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; + StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; + + if( TIArrayIndex == 0 ) + { + FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks; + } + } + else + { + StartIndirectBlock = 0; + } + + if( ByteOffset.QuadPart + WriteLength >= ByteOffsetTillHere + DoubleIndirectBlockSize) + { + EndIndirectBlock = DoubleIndirectBlockSize; + } + else + { + EndIndirectBlock = ByteOffset.QuadPart + WriteLength - ByteOffsetTillHere; + } + EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; + EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; + + { + ULONG i; + + for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ ) + { + VolumeByteOffset.QuadPart = TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize; + DebugTrace(DEBUG_TRACE_TRIPLE, "Single VolOffset = 0x%I64X", VolumeByteOffset ); + + if (!CcMapData( PtrVCB->PtrStreamFileObject, + &VolumeByteOffset, + LogicalBlockSize, + CanWait, + &PtrTIArray[ TIArrayIndex ].PtrBCB, + (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks)) + { + CompleteIrp = FALSE; + PostRequest = TRUE; + IoMarkIrpPending( PtrIrp ); + DIArrayCount = i; + try_return(RC = STATUS_PENDING); + + DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); + } + TIArrayIndex++; + } + } + CcUnpinData( TempDIBCB ); + TempDIBCB = NULL; + TempDIBuffer = NULL; + } + } + TIArrayCount = TIArrayIndex; + + DebugTrace(DEBUG_TRACE_TRIPLE, "TIArrayCount = %ld", TIArrayCount ); + DebugTrace(DEBUG_TRACE_TRIPLE, "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset ); + } + + // + // Allocating memory for IO Runs + // + Index = ( (WriteLength - 2) / LogicalBlockSize + 2 ); + PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) ) ); + + + Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) ); + BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart ); + + if( WriteLength > BytesRemaining ) + End = Start + BytesRemaining; + else + End = Start + WriteLength; + BytesWrittenSoFar = 0; + + Index = 0; + DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "\nDetermining the write IRPs that have to be passed down...", 0); + + while( 1 ) + { + BytesWrittenSoFar += (End-Start); + if( LogicalBlockIndex < EXT2_NDIR_BLOCKS ) + { + // Direct Block + PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ]; + } + else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) + { + // Single Indirect Block + PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - EXT2_NDIR_BLOCKS ]; + } + else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) + { + LONGLONG BlockNo; + LONGLONG IBlockIndex; + LONGLONG BlockIndex; + + BlockNo = LogicalBlockIndex - FirstCachedSIBlockOffset; + IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; + BlockIndex = BlockNo % NoOfSingleIndirectBlocks; + + // Double Indirect Block + PtrIoRuns[ Index ].LogicalBlock = + PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ]; + } + else + { + // Triple Indirect Block + LONGLONG BlockNo; + LONGLONG IBlockIndex; + LONGLONG BlockIndex; + BlockNo = LogicalBlockIndex - FirstCachedDIBlockOffset; + IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; + BlockIndex = BlockNo % NoOfSingleIndirectBlocks; + + DbgPrint( "\nBlock No : 0x%I64X IBlockIndex = 0x%I64X BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex); + + if( IBlockIndex >= TIArrayCount ) + { + Ext2BreakPoint(); + } + if( BlockIndex >= LogicalBlockSize ) + { + Ext2BreakPoint(); + } + + PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];; + DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock ); + } + + if( PtrIoRuns[ Index ].LogicalBlock == 0 ) + { + // + // Something is wrong... + // + Ext2BreakPoint(); + break; + + } + PtrIoRuns[ Index ].StartOffset = Start; + PtrIoRuns[ Index ].EndOffset = End; + PtrIoRuns[ Index ].PtrAssociatedIrp = NULL; + + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Index = (%ld)", LogicalBlockIndex ); + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Logical Block = (0x%lX)", PtrFCB->IBlock[ LogicalBlockIndex ] ); + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Start = (0x%lX)", Start ); + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " End = (0x%lX) ", End ); + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Bytes written (0x%lX)", BytesWrittenSoFar ); + + + + if( BytesWrittenSoFar >= WriteLength ) + break; + LogicalBlockIndex++; + Start = 0; + LeftOver = WriteLength - BytesWrittenSoFar; + if( LeftOver > LogicalBlockSize ) + End = LogicalBlockSize; + else + End = LeftOver; + // Loop over to make the write request... + Index++; + } + + // + // Unpin the Indirect Blocks + // + if( PtrPinnedSIndirectBCB ) + { + CcUnpinData( PtrPinnedSIndirectBCB ); + PtrPinnedSIndirectBCB = NULL; + PtrPinnedSIndirectBlock = NULL; + } + if( PtrPinnedDIndirectBCB ) + { + CcUnpinData( PtrPinnedDIndirectBCB ); + PtrPinnedDIndirectBCB = NULL; + PtrPinnedDIndirectBlock = NULL; + } + // + // Pass down Associated IRPs to the Target Device Driver... + // + DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "Passing down the Write IRPs to the disk driver...", 0 ); + + RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, WriteLength, PtrIrpContext, PtrFCB, SynchronousIo ); + + // + // Irp will be completed automatically + // when all the Associated IRPs are completed + // + if( RC == STATUS_SUCCESS || RC == STATUS_PENDING ) + { + CompleteIrp = FALSE; + } + try_return( RC ); + } + + try_exit: NOTHING; + + } + finally + { + if ( PtrIoRuns ) + { + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Write]", PtrIoRuns ); + ExFreePool( PtrIoRuns ); + } + if( PtrPinnedSIndirectBCB ) + { + CcUnpinData( PtrPinnedSIndirectBCB ); + PtrPinnedSIndirectBCB = NULL; + } + if( PtrPinnedDIndirectBCB ) + { + CcUnpinData( PtrPinnedDIndirectBCB ); + PtrPinnedDIndirectBCB = NULL; + } + if ( PtrDIArray ) + { + ULONG i; + for( i = 0; i < DIArrayCount; i++ ) + { + CcUnpinData( PtrDIArray->PtrBCB ); + } + DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrDIArray ); + ExFreePool( PtrDIArray ); + PtrDIArray = NULL; + } + // Release resources ... + // + if (PtrResourceAcquired) + { + Ext2ReleaseResource(PtrResourceAcquired); + + DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** Resource Released [Write]", 0); + DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Write]", + PtrResourceAcquired->ActiveCount, + PtrResourceAcquired->NumberOfExclusiveWaiters, + PtrResourceAcquired->NumberOfSharedWaiters ); + + if( PtrFileObject ) + { + DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Write]", PtrFileObject); + } + if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Write]", 0); + } + else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Released [Write]", 0); + } + else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Paging Resource Released [Write]", 0); + } + else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) ) + { + DebugTrace(DEBUG_TRACE_MISC, "*** FCB Resource Released [Write]", 0); + } + else + { + DebugTrace(DEBUG_TRACE_MISC, "*** Unknown Resource Released [Write]", 0); + } + + PtrResourceAcquired = NULL; + } + + if (PostRequest) + { + RC = Ext2PostRequest(PtrIrpContext, PtrIrp); + } + else if ( CompleteIrp && !(RC == STATUS_PENDING)) + { + // For synchronous I/O, the FSD must maintain the current byte offset + // Do not do this however, if I/O is marked as paging-io + if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) + { + PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset, + RtlConvertUlongToLargeInteger((unsigned long)NumberBytesWritten)); + } + + // If the write completed successfully and this was not a paging-io + // operation, set a flag in the CCB that indicates that a write was + // performed and that the file time should be updated at cleanup + if (NT_SUCCESS(RC) && !PagingIo) + { + Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_MODIFIED); + } + + // If the file size was changed, set a flag in the FCB indicating that + // this occurred. + + // If the request failed, and we had done some nasty stuff like + // extending the file size (including informing the Cache Manager + // about the new file size), and allocating on-disk space etc., undo + // it at this time. + + // Can complete the IRP here if no exception was encountered + if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) + { + PtrIrp->IoStatus.Status = RC; + PtrIrp->IoStatus.Information = NumberBytesWritten; + + // complete the IRP + IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); + } + + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + + } // can we complete the IRP ? + else + { + // Free up the Irp Context + Ext2ReleaseIrpContext(PtrIrpContext); + } + } // end of "finally" processing + return(RC); +} + + +/************************************************************************* +* +* Function: Ext2DeferredWriteCallBack() +* +* Description: +* Invoked by the cache manager in the context of a worker thread. +* Typically, you can simply post the request at this point (just +* as you would have if the original request could not block) to +* perform the write in the context of a system worker thread. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +void Ext2DeferredWriteCallBack ( +void *Context1, // Should be PtrIrpContext +void *Context2 ) // Should be PtrIrp +{ + // You should typically simply post the request to your internal + // queue of posted requests (just as you would if the original write + // could not be completed because the caller could not block). + // Once you post the request, return from this routine. The write + // will then be retried in the context of a system worker thread +} diff --git a/reactos/drivers/filesystems/fs_rec/ext2.c b/reactos/drivers/filesystems/fs_rec/ext2.c new file mode 100644 index 00000000000..2fa7339cadb --- /dev/null +++ b/reactos/drivers/filesystems/fs_rec/ext2.c @@ -0,0 +1,136 @@ +/* + * ReactOS kernel + * Copyright (C) 2002,2003 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: fat.c 9284 2004-05-02 20:12:38Z hbirr $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: drivers/fs/fs_rec/ext2.c (based on vfat.c) + * PURPOSE: Filesystem recognizer driver + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include + +#include "fs_rec.h" + + +/* FUNCTIONS ****************************************************************/ + +static NTSTATUS +FsRecIsExt2Volume(IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + PARTITION_INFORMATION PartitionInfo; + DISK_GEOMETRY DiskGeometry; + ULONG Size; + BOOL RecognizedFS = FALSE; + Size = sizeof(DISK_GEOMETRY); + + Status = FsRecDeviceIoControl(DeviceObject, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &DiskGeometry, + &Size); + if (!NT_SUCCESS(Status)) + { + DPRINT("FsRecDeviceIoControl faild (%x)\n", Status); + return Status; + } + if (DiskGeometry.MediaType == FixedMedia || DiskGeometry.MediaType == RemovableMedia) + { + // We have found a hard disk + Size = sizeof(PARTITION_INFORMATION); + Status = FsRecDeviceIoControl(DeviceObject, + IOCTL_DISK_GET_PARTITION_INFO, + NULL, + 0, + &PartitionInfo, + &Size); + if (!NT_SUCCESS(Status)) + { + DPRINT("FsRecDeviceIoControl faild (%x)\n", Status); + return Status; + } + + if (PartitionInfo.PartitionType) + { + if (PartitionInfo.PartitionType == PARTITION_EXT2) + { + RecognizedFS = TRUE; + } + } + } + + return RecognizedFS ? STATUS_SUCCESS : STATUS_UNRECOGNIZED_VOLUME; +} + + +NTSTATUS +FsRecExt2FsControl(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION Stack; + UNICODE_STRING RegistryPath; + NTSTATUS Status; + + Stack = IoGetCurrentIrpStackLocation(Irp); + + switch (Stack->MinorFunction) + { + case IRP_MN_MOUNT_VOLUME: + DPRINT("FAT: IRP_MN_MOUNT_VOLUME\n"); + Status = FsRecIsExt2Volume(Stack->Parameters.MountVolume.DeviceObject); + if (NT_SUCCESS(Status)) + { + DPRINT("Identified FAT volume\n"); + Status = STATUS_FS_DRIVER_REQUIRED; + } + break; + + case IRP_MN_LOAD_FILE_SYSTEM: + DPRINT("FAT: IRP_MN_LOAD_FILE_SYSTEM\n"); + RtlRosInitUnicodeStringFromLiteral(&RegistryPath, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Ext2"); + Status = ZwLoadDriver(&RegistryPath); + if (!NT_SUCCESS(Status)) + { + DPRINT("ZwLoadDriver failed (Status %x)\n", Status); + } + else + { + IoUnregisterFileSystem(DeviceObject); + } + break; + + default: + DPRINT("FAT: Unknown minor function %lx\n", Stack->MinorFunction); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + return(Status); +} + +/* EOF */ diff --git a/reactos/include/reactos/libs/fslib/ext2lib.h b/reactos/include/reactos/libs/fslib/ext2lib.h new file mode 100644 index 00000000000..58390b0310a --- /dev/null +++ b/reactos/include/reactos/libs/fslib/ext2lib.h @@ -0,0 +1,26 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS EXT2 filesystem library + * FILE: include/fslib/ext2lib.h + * PURPOSE: Public definitions for ext2 filesystem library + */ +#ifndef __EXT2LIB_H +#define __EXT2LIB_H + +#include + +NTSTATUS +Ext2Initialize (VOID); + +NTSTATUS +Ext2Cleanup (VOID); + +NTSTATUS +Ext2Format (PUNICODE_STRING DriveRoot, + ULONG MediaFlag, + PUNICODE_STRING Label, + BOOLEAN QuickFormat, + ULONG ClusterSize, + PFMIFSCALLBACK Callback); + +#endif /*__EXT2LIB_H */ diff --git a/reactos/lib/fslib/ext2lib/Badblock.c b/reactos/lib/fslib/ext2lib/Badblock.c new file mode 100644 index 00000000000..28567b24cd1 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Badblock.c @@ -0,0 +1,43 @@ +/* + * PROJECT: Mke2fs + * FILE: Badblock.c + * PROGRAMMER: Matt Wu + * 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; +} diff --git a/reactos/lib/fslib/ext2lib/Bitmap.c b/reactos/lib/fslib/ext2lib/Bitmap.c new file mode 100644 index 00000000000..cf5a15713c8 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Bitmap.c @@ -0,0 +1,499 @@ +/* + * PROJECT: Mke2fs + * FILE: Bitmap.c + * PROGRAMMER: Matt Wu + * 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); +} + diff --git a/reactos/lib/fslib/ext2lib/Bitmap.h b/reactos/lib/fslib/ext2lib/Bitmap.h new file mode 100644 index 00000000000..cbac01c8ddd --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Bitmap.h @@ -0,0 +1,12 @@ +#ifndef _BITMAP_H + +#include "time.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "windows.h" + + + + +#endif // _BITMAP_H diff --git a/reactos/lib/fslib/ext2lib/Disk.c b/reactos/lib/fslib/ext2lib/Disk.c new file mode 100644 index 00000000000..1930aad4952 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Disk.c @@ -0,0 +1,1352 @@ +/* + * PROJECT: Mke2fs + * FILE: Disk.c + * PROGRAMMER: Matt Wu + * 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; +} diff --git a/reactos/lib/fslib/ext2lib/Disk.h b/reactos/lib/fslib/ext2lib/Disk.h new file mode 100644 index 00000000000..d23a14a4b33 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Disk.h @@ -0,0 +1,19 @@ +/* + * PROJECT: Mke2fs + * FILE: Disk.h + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +#ifndef _DISK_H_ +#define _DISK_H_ + +/* INCLUDES **************************************************************/ + +#include "Stdafx.h" + +/* DEFINITIONS ***********************************************************/ + + + +#endif /* _DISK_H_ */ diff --git a/reactos/lib/fslib/ext2lib/Group.c b/reactos/lib/fslib/ext2lib/Group.c new file mode 100644 index 00000000000..68ea9745651 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Group.c @@ -0,0 +1,68 @@ +/* + * PROJECT: Mke2fs + * FILE: Group.c + * PROGRAMMER: Matt Wu + * 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; + } +} diff --git a/reactos/lib/fslib/ext2lib/Inode.c b/reactos/lib/fslib/ext2lib/Inode.c new file mode 100644 index 00000000000..9b235978c70 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Inode.c @@ -0,0 +1,697 @@ +/* + * PROJECT: Mke2fs + * FILE: Inode.c + * PROGRAMMER: Matt Wu + * 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; +} diff --git a/reactos/lib/fslib/ext2lib/Memory.c b/reactos/lib/fslib/ext2lib/Memory.c new file mode 100644 index 00000000000..08e59f79b98 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Memory.c @@ -0,0 +1,416 @@ +/* + * PROJECT: Mke2fs + * FILE: Memory.c + * PROGRAMMER: Matt Wu + * 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; +} diff --git a/reactos/lib/fslib/ext2lib/Mke2fs.c b/reactos/lib/fslib/ext2lib/Mke2fs.c new file mode 100644 index 00000000000..9434371b875 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Mke2fs.c @@ -0,0 +1,1010 @@ +/* + * PROJECT: Mke2fs + * FILE: Disk.c + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +/* INCLUDES **************************************************************/ + +#include "Mke2fs.h" +#include + +/* 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; +} diff --git a/reactos/lib/fslib/ext2lib/Mke2fs.h b/reactos/lib/fslib/ext2lib/Mke2fs.h new file mode 100644 index 00000000000..ea05d529c01 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Mke2fs.h @@ -0,0 +1,876 @@ +/* + * PROJECT: Mke2fs + * FILE: Mke2fs.h + * PROGRAMMER: Matt Wu + * HOMEPAGE: http://ext2.yeah.net + */ + +#ifndef __MKE2FS__INCLUDE__ +#define __MKE2FS__INCLUDE__ + + +/* INCLUDES **************************************************************/ + + +#include +#include +#include +#include + +#include + +#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__ diff --git a/reactos/lib/fslib/ext2lib/Super.c b/reactos/lib/fslib/ext2lib/Super.c new file mode 100644 index 00000000000..0b09490efda --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Super.c @@ -0,0 +1,302 @@ +/* + * PROJECT: Mke2fs + * FILE: Super.c + * PROGRAMMER: Matt Wu + * 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; +} diff --git a/reactos/lib/fslib/ext2lib/Uuid.c b/reactos/lib/fslib/ext2lib/Uuid.c new file mode 100644 index 00000000000..5284cd94b1b --- /dev/null +++ b/reactos/lib/fslib/ext2lib/Uuid.c @@ -0,0 +1,25 @@ +/* + * PROJECT: Mke2fs + * FILE: Timer.c + * PROGRAMMER: Matt Wu + * 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 +} diff --git a/reactos/lib/fslib/ext2lib/ext2_fs.h b/reactos/lib/fslib/ext2lib/ext2_fs.h new file mode 100644 index 00000000000..be4cafa5ae7 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/ext2_fs.h @@ -0,0 +1,657 @@ +/* + * 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 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 */ diff --git a/reactos/lib/fslib/ext2lib/types.h b/reactos/lib/fslib/ext2lib/types.h new file mode 100644 index 00000000000..a874df5b564 --- /dev/null +++ b/reactos/lib/fslib/ext2lib/types.h @@ -0,0 +1,10 @@ +#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 */