From: Hervé Poussineau Date: Mon, 11 Feb 2008 12:10:35 +0000 (+0000) Subject: Bring back ext2 code from branch X-Git-Tag: backups/hyperion@33110~752 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=0ba562cefad2799d226f2a2443b9abd8fdc3e79e Bring back ext2 code from branch It does not compile yet svn path=/trunk/; revision=32283 --- 0ba562cefad2799d226f2a2443b9abd8fdc3e79e diff --cc reactos/drivers/filesystems/ext2/ext2fs.rc index 00000000000,00000000000..0cbc172a885 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/ext2fs.rc @@@ -1,0 -1,0 +1,7 @@@ ++/* $Id: ext2fs.rc 12852 2005-01-06 13:58:04Z mf $ */ ++ ++#define REACTOS_VERSION_DLL ++#define REACTOS_STR_FILE_DESCRIPTION "Linux ext2 IFS Driver\0" ++#define REACTOS_STR_INTERNAL_NAME "ext2fs\0" ++#define REACTOS_STR_ORIGINAL_FILENAME "ext2fs.sys\0" ++#include diff --cc reactos/drivers/filesystems/ext2/inc/errmsg.h index 00000000000,00000000000..8f8ac96eeb2 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/errmsg.h @@@ -1,0 -1,0 +1,68 @@@ ++/************************************************************************* ++* ++* File: errmsg.msg ++* ++* Product: Ext2 FSD ++* ++* Module: Ext2 FSD Event Log Messages ++* ++* Description: ++* Contains error strings in a format understandable to the message compiler. ++* Please compile (using mc) with the -c option which will set the ++* "Customer" bit in all errors. ++* Use values beginning at 0xA000 (e.g. 0xA001) for the Ext2 FSD ++* errors. ++* Do NOT use %1 for insertion strings. The I/O manager assumes that ++* the first insertion string is the name of the driver/device. ++* ++* ++*************************************************************************/ ++// ++// Values are 32 bit values layed out as follows: ++// ++// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 ++// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 ++// +---+-+-+-----------------------+-------------------------------+ ++// |Sev|C|R| Facility | Code | ++// +---+-+-+-----------------------+-------------------------------+ ++// ++// where ++// ++// Sev - is the severity code ++// ++// 00 - Success ++// 01 - Informational ++// 10 - Warning ++// 11 - Error ++// ++// C - is the Customer code flag ++// ++// R - is a reserved bit ++// ++// Facility - is the facility code ++// ++// Code - is the facility's status code ++// ++// ++// Define the facility codes ++// ++ ++ ++// ++// Define the severity codes ++// ++#define STATUS_SEVERITY_WARNING 0x2 ++#define STATUS_SEVERITY_SUCCESS 0x0 ++#define STATUS_SEVERITY_INFORMATIONAL 0x1 ++#define STATUS_SEVERITY_ERROR 0x3 ++ ++ ++// ++// MessageId: EXT2_ERROR_INTERNAL_ERROR ++// ++// MessageText: ++// ++// The Ext2 FSD encountered an internal error. Please check log data information. ++// ++#define EXT2_ERROR_INTERNAL_ERROR ((ULONG)0xE004A001L) ++ diff --cc reactos/drivers/filesystems/ext2/inc/ext2_fs.h index 00000000000,00000000000..4a545d4d307 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/ext2_fs.h @@@ -1,0 -1,0 +1,615 @@@ ++/* ++ * linux/include/linux/ext2_fs.h ++ * ++ * Copyright (C) 1992, 1993, 1994, 1995 ++ * Remy Card (card@masi.ibp.fr) ++ * Laboratoire MASI - Institut Blaise Pascal ++ * Universite Pierre et Marie Curie (Paris VI) ++ * ++ * from ++ * ++ * linux/include/linux/minix_fs.h ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ */ ++ ++#ifndef _LINUX_EXT2_FS_H ++#define _LINUX_EXT2_FS_H ++ ++// #include ++ ++/* ++ * 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 --cc reactos/drivers/filesystems/ext2/inc/ext2fsd.h index 00000000000,00000000000..81c246d43d5 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/ext2fsd.h @@@ -1,0 -1,0 +1,250 @@@ ++/************************************************************************* ++* ++* File: ext2fsd.h ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* The main include file for the Ext2 file system driver. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++ ++#ifndef _EXT2_FSD_H_ ++#define _EXT2_FSD_H_ ++ ++#define EXT2_POOL_WITH_TAG ++ ++ ++// some constant definitions ++#define EXT2_PANIC_IDENTIFIER (0x86427531) ++ ++// any directory information EXT2 obtains from the local file system ++// will use a buffer of the following size ... (in KB) ++#define EXT2_READ_DIR_BUFFER_LENGTH (512) ++#define EXT2_MAXCLOSABLE_FCBS_UL 20 ++#define EXT2_MAXCLOSABLE_FCBS_LL 10 ++ ++// Some type definitions... ++// These are used later... ++ ++typedef unsigned char UCHAR; ++typedef unsigned int UINT; ++typedef UCHAR BYTE; ++typedef UCHAR BOOLEAN; // winnt ++typedef BOOLEAN * PBOOLEAN; // winnt ++typedef void * PVOID64; // winnt ++typedef long LONG; ++typedef LONG HRESULT; ++ ++ ++#if defined(_M_IX86) ++#define FASTCALL _fastcall ++#else ++#define FASTCALL ++#endif ++ ++ ++ ++// Common include files - should be in the include dir of the MS supplied IFS Kit ++#include ++#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 --cc reactos/drivers/filesystems/ext2/inc/ext2metadata.h index 00000000000,00000000000..bbe240e9143 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/ext2metadata.h @@@ -1,0 -1,0 +1,115 @@@ ++/************************************************************************* ++* ++* File: ext2metadata.h ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains the definitions for the Ext2 Metadata structures. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#ifndef EXT2_METADATA_STRUCTURES ++#define EXT2_METADATA_STRUCTURES ++ ++// ++// Some type definitions... ++// These are used in the ext2_fs.h header file ++// ++typedef unsigned int __u32 ; ++typedef signed int __s32 ; ++typedef unsigned short int __u16 ; ++typedef signed short int __s16 ; ++typedef unsigned char __u8 ; ++ ++// ++//****************************************************** ++// ++// Using Remy Card's (slightly modified) Ext2 header... ++// ++#include "ext2_fs.h" ++// ++//****************************************************** ++// ++ ++typedef struct ext2_super_block EXT2_SUPER_BLOCK; ++typedef EXT2_SUPER_BLOCK * PEXT2_SUPER_BLOCK; ++ ++typedef struct ext2_inode EXT2_INODE; ++typedef EXT2_INODE * PEXT2_INODE; ++ ++typedef struct ext2_group_desc EXT2_GROUP_DESCRIPTOR; ++typedef EXT2_GROUP_DESCRIPTOR * PEXT2_GROUP_DESCRIPTOR; ++ ++typedef struct ext2_dir_entry_2 EXT2_DIR_ENTRY; ++typedef EXT2_DIR_ENTRY * PEXT2_DIR_ENTRY; ++ ++// ++// Ext2 Supported File Types... ++// ++#define IMODE_FIFO 0x01 ++#define IMODE_CHARDEV 0x02 ++#define IMODE_DIR 0x04 ++#define IMODE_BLOCKDEV 0x06 ++#define IMODE_FILE 0x08 ++#define IMODE_SLINK 0x0A ++#define IMODE_SOCKET 0x0C ++ ++#define _MKMODE(m) ( ( (m) >> 12 ) & 0x000F) ++#define Ext2IsModeRegularFile(m) ( _MKMODE(m) == IMODE_FILE ) ++#define Ext2IsModeDirectory(m) ( _MKMODE(m) == IMODE_DIR ) ++#define Ext2IsModeSymbolicLink(m) ( _MKMODE(m) == IMODE_SLINK ) ++#define Ext2IsModePipe(m) ( _MKMODE(m) == IMODE_FIFO ) ++#define Ext2IsModeCharacterDevice(m) ( _MKMODE(m) == IMODE_CHARDEV ) ++#define Ext2IsModeBlockDevice(m) ( _MKMODE(m) == IMODE_BLOCKDEV ) ++#define Ext2IsModeSocket(m) ( _MKMODE(m) == IMODE_SOCKET ) ++ ++#define Ext2IsModeHidden(m) ( (m & 0x124) == 0) // No Read Permission ++#define Ext2IsModeReadOnly(m) ( (m & 0x92) == 0) // No write Permission ++ ++#define Ext2SetModeHidden(m) m = (m & (~0x124)); // Turn off Read Permission ++#define Ext2SetModeReadOnly(m) m = (m & (~0x92)); // Turn off write Permission ++#define Ext2SetModeReadWrite(m) m = (m & 0x1ff); // Set read/write Permission ++ ++ ++// ++// Define the Packed and Unpacked BIOS Parameter Block ++// ++typedef struct _PACKED_BIOS_PARAMETER_BLOCK { ++ UCHAR BytesPerSector[2]; // offset = 0x000 0 ++ UCHAR SectorsPerCluster[1]; // offset = 0x002 2 ++ UCHAR ReservedSectors[2]; // offset = 0x003 3 ++ UCHAR Fats[1]; // offset = 0x005 5 ++ UCHAR RootEntries[2]; // offset = 0x006 6 ++ UCHAR Sectors[2]; // offset = 0x008 8 ++ UCHAR Media[1]; // offset = 0x00A 10 ++ UCHAR SectorsPerFat[2]; // offset = 0x00B 11 ++ UCHAR SectorsPerTrack[2]; // offset = 0x00D 13 ++ UCHAR Heads[2]; // offset = 0x00F 15 ++ UCHAR HiddenSectors[4]; // offset = 0x011 17 ++ UCHAR LargeSectors[4]; // offset = 0x015 21 ++} PACKED_BIOS_PARAMETER_BLOCK; // sizeof = 0x019 25 ++typedef PACKED_BIOS_PARAMETER_BLOCK *PPACKED_BIOS_PARAMETER_BLOCK; ++ ++// ++// Define the boot sector ++// ++typedef struct _PACKED_BOOT_SECTOR { ++ UCHAR Jump[3]; // offset = 0x000 0 ++ UCHAR Oem[8]; // offset = 0x003 3 ++ PACKED_BIOS_PARAMETER_BLOCK PackedBpb; // offset = 0x00B 11 ++ UCHAR PhysicalDriveNumber; // offset = 0x024 36 ++ UCHAR CurrentHead; // offset = 0x025 37 ++ UCHAR Signature; // offset = 0x026 38 ++ UCHAR Id[4]; // offset = 0x027 39 ++ UCHAR VolumeLabel[11]; // offset = 0x02B 43 ++ UCHAR SystemId[8]; // offset = 0x036 54 ++} PACKED_BOOT_SECTOR; // sizeof = 0x03E 62 ++ ++typedef PACKED_BOOT_SECTOR *PPACKED_BOOT_SECTOR; ++ ++ ++#endif diff --cc reactos/drivers/filesystems/ext2/inc/protos.h index 00000000000,00000000000..1cb7c134d62 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/protos.h @@@ -1,0 -1,0 +1,782 @@@ ++/************************************************************************* ++* ++* File: protos.h ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains the prototypes for functions in this sample FSD. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#ifndef _EXT2_PROTOS_H_ ++#define _EXT2_PROTOS_H_ ++ ++#ifdef __REACTOS__ ++typedef PIO_STACK_LOCATION PEXTENDED_IO_STACK_LOCATION; ++#endif ++ ++/************************************************************************* ++* Prototypes for the file sfsdinit.c ++*************************************************************************/ ++extern NTSTATUS STDCALL DriverEntry( ++ PDRIVER_OBJECT DriverObject, // created by the I/O sub-system ++ PUNICODE_STRING RegistryPath); // path to the registry key ++ ++extern void STDCALL Ext2FsdInitializeFunctionPointers( ++ PDRIVER_OBJECT DriverObject); // created by the I/O sub-system ++ ++ ++extern VOID STDCALL Ext2QueueHandlerThread( ++ IN PVOID StartContext); ++ ++/************************************************************************* ++* Prototypes for the file fsctrl.c ++*************************************************************************/ ++ ++extern NTSTATUS STDCALL Ext2FileSystemControl( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp ++ ); ++ ++extern NTSTATUS STDCALL Ext2VerifyVolume ( ++ IN PIRP Irp, ++ IN PIO_STACK_LOCATION IrpSp ); ++ ++ ++/************************************************************************* ++* Prototypes for the file create.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2Create( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonCreate( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++BOOLEAN FirstAttempt ); ++ ++extern NTSTATUS STDCALL Ext2OpenVolume( ++ PtrExt2VCB PtrVCB, // volume to be opened ++ PtrExt2IrpContext PtrIrpContext, // IRP context ++ PIRP PtrIrp, // original/user IRP ++ unsigned short ShareAccess, // share access ++ PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) ++ PFILE_OBJECT PtrNewFileObject); // I/O Mgr. created file object ++ ++extern NTSTATUS STDCALL Ext2OpenRootDirectory( ++ PtrExt2VCB PtrVCB, // volume to be opened ++ PtrExt2IrpContext PtrIrpContext, // IRP context ++ PIRP PtrIrp, // original/user IRP ++ unsigned short ShareAccess, // share access ++ PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) ++ PFILE_OBJECT PtrNewFileObject); // I/O Mgr. created file object ++ ++extern void STDCALL Ext2InitializeFCB( ++ PtrExt2FCB PtrNewFCB, // FCB structure to be initialized ++ PtrExt2VCB PtrVCB, // logical volume (VCB) pointer ++ PtrExt2ObjectName PtrObjectName, // name of the object ++ uint32 Flags, // is this a file/directory, etc. ++ PFILE_OBJECT PtrFileObject);// optional file object to be initialized ++ ++extern PtrExt2FCB STDCALL Ext2LocateChildFCBInCore( ++ PtrExt2VCB PtrVCB, ++ PUNICODE_STRING PtrName, ++ ULONG ParentInodeNo ); ++ ++extern PtrExt2FCB STDCALL Ext2LocateFCBInCore( ++ PtrExt2VCB PtrVCB, ++ ULONG InodeNo ); ++ ++ ++extern ULONG STDCALL Ext2LocateFileInDisk( ++ PtrExt2VCB PtrVCB, ++ PUNICODE_STRING PtrCurrentName, ++ PtrExt2FCB PtrParentFCB, ++ ULONG *Type ); ++ ++extern ULONG STDCALL Ext2CreateFile( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ PUNICODE_STRING PtrName, ++ PtrExt2FCB PtrParentFCB, ++ ULONG Type); ++ ++extern BOOLEAN STDCALL Ext2OverwriteFile( ++ PtrExt2FCB PtrFCB, ++ PtrExt2IrpContext PtrIrpContext); ++ ++extern BOOLEAN STDCALL Ext2SupersedeFile( ++ PtrExt2FCB PtrFCB, ++ PtrExt2IrpContext PtrIrpContext); ++ ++/************************************************************************* ++* Prototypes for the file misc.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2InitializeZones( ++void); ++ ++extern void STDCALL Ext2DestroyZones( ++void); ++ ++extern BOOLEAN STDCALL Ext2IsIrpTopLevel( ++PIRP Irp); // the IRP sent to our dispatch routine ++ ++extern long STDCALL Ext2ExceptionFilter( ++PtrExt2IrpContext PtrIrpContext, ++PEXCEPTION_POINTERS PtrExceptionPointers); ++ ++extern NTSTATUS STDCALL Ext2ExceptionHandler( ++PtrExt2IrpContext PtrIrpContext, ++PIRP Irp); ++ ++extern void STDCALL Ext2LogEvent( ++NTSTATUS Ext2EventLogId, // the Ext2 private message id ++NTSTATUS RC); // any NT error code we wish to log ... ++ ++extern PtrExt2ObjectName STDCALL Ext2AllocateObjectName( ++void); ++ ++extern void STDCALL Ext2ReleaseObjectName( ++PtrExt2ObjectName PtrObjectName); ++ ++extern PtrExt2CCB STDCALL Ext2AllocateCCB( ++void ); ++ ++extern PtrExt2FCB STDCALL Ext2GetUsedFCB( ++PtrExt2VCB PtrVCB ); ++ ++extern BOOLEAN STDCALL Ext2CloseClosableFCB( ++PtrExt2FCB PtrFCB ); ++ ++extern void STDCALL Ext2ReleaseCCB( ++PtrExt2CCB PtrCCB); ++ ++extern PtrExt2FCB STDCALL Ext2AllocateFCB( ++void); ++ ++extern NTSTATUS STDCALL Ext2CreateNewFCB( ++PtrExt2FCB *ReturnedFCB, ++LARGE_INTEGER AllocationSize, ++LARGE_INTEGER EndOfFile, ++PFILE_OBJECT PtrFileObject, ++PtrExt2VCB PtrVCB, ++PtrExt2ObjectName PtrObjectName); ++ ++extern NTSTATUS STDCALL Ext2CreateNewCCB( ++PtrExt2CCB *ReturnedCCB, ++PtrExt2FCB PtrFCB, ++PFILE_OBJECT PtrFileObject); ++ ++extern void STDCALL Ext2ReleaseFCB( ++PtrExt2FCB PtrFCB); ++ ++extern PtrExt2FileLockInfo STDCALL Ext2AllocateByteLocks( ++void); ++ ++extern void STDCALL Ext2ReleaseByteLocks( ++PtrExt2FileLockInfo PtrByteLocks); ++ ++extern PtrExt2IrpContext STDCALL Ext2AllocateIrpContext( ++PIRP Irp, ++PDEVICE_OBJECT PtrTargetDeviceObject); ++ ++extern void STDCALL Ext2ReleaseIrpContext( ++PtrExt2IrpContext PtrIrpContext); ++ ++extern NTSTATUS STDCALL Ext2PostRequest( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp); ++ ++extern void STDCALL Ext2CommonDispatch( ++void *Context); // actually an IRPContext structure ++ ++extern void STDCALL Ext2InitializeVCB( ++PDEVICE_OBJECT PtrVolumeDeviceObject, ++PDEVICE_OBJECT PtrTargetDeviceObject, ++PVPB PtrVPB, ++PLARGE_INTEGER AllocationSize); ++ ++extern void STDCALL Ext2CompleteRequest( ++ IN PIRP Irp OPTIONAL, ++ IN NTSTATUS Status ++ ); ++ ++extern NTSTATUS STDCALL Ext2DenyAccess( ++ IN PIRP Irp ++ ); ++extern NTSTATUS STDCALL Ext2GetFCB_CCB_VCB_FromFileObject( ++ IN PFILE_OBJECT PtrFileObject, ++ OUT PtrExt2FCB *PPtrFCB, ++ OUT PtrExt2CCB *PPtrCCB, ++ OUT PtrExt2VCB *PPtrVCB ); ++ ++extern void STDCALL Ext2CopyUnicodeString( ++ IN OUT PUNICODE_STRING PtrDestinationString, ++ IN PUNICODE_STRING PtrSourceString ); ++ ++extern void STDCALL Ext2CopyWideCharToUnicodeString( ++ IN OUT PUNICODE_STRING PtrDestinationString, ++ IN PCWSTR PtrSourceString ); ++ ++extern void STDCALL Ext2CopyCharToUnicodeString( ++ IN OUT PUNICODE_STRING PtrDestinationString, ++ IN PCSTR PtrSourceString, ++ IN USHORT SourceStringLength ); ++ ++extern void STDCALL Ext2CopyZCharToUnicodeString( ++ IN OUT PUNICODE_STRING PtrDestinationString, ++ IN PCSTR PtrSourceString ); ++ ++extern void STDCALL Ext2DeallocateUnicodeString( ++ PUNICODE_STRING PtrUnicodeString ); ++ ++extern void STDCALL Ext2ZerooutUnicodeString( ++ PUNICODE_STRING PtrUnicodeString ); ++ ++extern BOOLEAN STDCALL Ext2SaveBCB( ++ PtrExt2IrpContext PtrIrpContext, ++ PBCB PtrBCB, ++ PFILE_OBJECT PtrFileObject); ++ ++extern BOOLEAN STDCALL Ext2FlushSavedBCBs( ++ PtrExt2IrpContext PtrIrpContext); ++ ++extern BOOLEAN STDCALL AssertBCB( ++ PBCB PtrBCB); ++ ++extern ULONG STDCALL Ext2Align( ++ ULONG NumberToBeAligned, ++ ULONG Alignment); ++ ++extern LONGLONG STDCALL Ext2Align64( ++ LONGLONG NumberToBeAligned, ++ LONGLONG Alignment); ++ ++extern ULONG STDCALL Ext2GetCurrentTime(); ++ ++/************************************************************************* ++* Prototypes for the file cleanup.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2Cleanup( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonCleanup( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++BOOLEAN FirstAttempt ); ++ ++/************************************************************************* ++* Prototypes for the file close.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2Close( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonClose( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++BOOLEAN FirstAttempt ); ++ ++/************************************************************************* ++* Prototypes for the file read.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2Read( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonRead( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++BOOLEAN FirstAttempt ); ++ ++extern void * STDCALL Ext2GetCallersBuffer( ++PIRP PtrIrp); ++ ++extern NTSTATUS STDCALL Ext2LockCallersBuffer( ++PIRP PtrIrp, ++BOOLEAN IsReadOperation, ++uint32 Length); ++ ++extern void STDCALL Ext2MdlComplete( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++PIO_STACK_LOCATION PtrIoStackLocation, ++BOOLEAN ReadCompletion); ++ ++/************************************************************************* ++* Prototypes for the file write.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2Write( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonWrite( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp); ++ ++extern void STDCALL Ext2DeferredWriteCallBack ( ++void *Context1, // Should be PtrIrpContext ++void *Context2); // Should be PtrIrp ++ ++/************************************************************************* ++* Prototypes for the file fileinfo.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2FileInfo( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonFileInfo( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp); ++ ++extern NTSTATUS STDCALL Ext2GetBasicInformation( ++ PtrExt2FCB PtrFCB, ++ PFILE_BASIC_INFORMATION PtrBuffer, ++ long *PtrReturnedLength); ++ ++extern NTSTATUS STDCALL Ext2GetStandardInformation( ++ PtrExt2FCB PtrFCB, ++ PFILE_STANDARD_INFORMATION PtrStdInformation, ++ long *PtrReturnedLength); ++ ++extern NTSTATUS STDCALL Ext2GetNetworkOpenInformation( ++ PtrExt2FCB PtrFCB, ++ PFILE_NETWORK_OPEN_INFORMATION PtrNetworkOpenInformation, ++ long *PtrReturnedLength ); ++ ++extern NTSTATUS STDCALL Ext2GetFullNameInformation( ++ PtrExt2FCB PtrFCB, ++ PtrExt2CCB PtrCCB, ++ PFILE_NAME_INFORMATION PtrNameInformation, ++ long *PtrReturnedLength); ++ ++extern NTSTATUS STDCALL Ext2SetBasicInformation( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2FCB PtrFCB, ++ PFILE_OBJECT PtrFileObject, ++ PFILE_BASIC_INFORMATION PtrFileInformation ); ++ ++extern NTSTATUS STDCALL Ext2SetDispositionInformation( ++PtrExt2FCB PtrFCB, ++PtrExt2CCB PtrCCB, ++PtrExt2VCB PtrVCB, ++PFILE_OBJECT PtrFileObject, ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++PFILE_DISPOSITION_INFORMATION PtrBuffer); ++ ++extern NTSTATUS STDCALL Ext2SetAllocationInformation( ++PtrExt2FCB PtrFCB, ++PtrExt2CCB PtrCCB, ++PtrExt2VCB PtrVCB, ++PFILE_OBJECT PtrFileObject, ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++PFILE_ALLOCATION_INFORMATION PtrBuffer); ++ ++/************************************************************************* ++* Prototypes for the file flush.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2Flush( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonFlush( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp); ++ ++extern void STDCALL Ext2FlushAFile( ++PtrExt2NTRequiredFCB PtrReqdFCB, ++PIO_STATUS_BLOCK PtrIoStatus); ++ ++extern void STDCALL Ext2FlushLogicalVolume( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++PtrExt2VCB PtrVCB); ++ ++extern NTSTATUS STDCALL Ext2FlushCompletion( ++PDEVICE_OBJECT PtrDeviceObject, ++PIRP PtrIrp, ++PVOID Context); ++ ++/************************************************************************* ++* Prototypes for the file dircntrl.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2DirControl( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonDirControl( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp); ++ ++extern NTSTATUS STDCALL Ext2QueryDirectory( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, ++PFILE_OBJECT PtrFileObject, ++PtrExt2FCB PtrFCB, ++PtrExt2CCB PtrCCB); ++ ++extern NTSTATUS STDCALL Ext2NotifyChangeDirectory( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, ++PFILE_OBJECT PtrFileObject, ++PtrExt2FCB PtrFCB, ++PtrExt2CCB PtrCCB); ++ ++/************************************************************************* ++* Prototypes for the file devcntrl.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2DeviceControl( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonDeviceControl( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp); ++ ++extern NTSTATUS STDCALL Ext2DevIoctlCompletion( ++PDEVICE_OBJECT PtrDeviceObject, ++PIRP PtrIrp, ++void *Context); ++ ++extern NTSTATUS STDCALL Ext2HandleQueryPath( ++void *BufferPointer); ++ ++/************************************************************************* ++* Prototypes for the file shutdown.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2Shutdown( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++extern NTSTATUS STDCALL Ext2CommonShutdown( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp); ++ ++/************************************************************************* ++* Prototypes for the file volinfo.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2QueryVolInfo( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp); // I/O Request Packet ++ ++NTSTATUS STDCALL Ext2SetVolInfo( ++ IN PDEVICE_OBJECT DeviceObject, // the logical volume device object ++ IN PIRP Irp); // I/O Request Packet ++ ++ ++/************************************************************************* ++* Prototypes for the file fastio.c ++*************************************************************************/ ++extern BOOLEAN STDCALL Ext2FastIoCheckIfPossible( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN BOOLEAN Wait, ++IN ULONG LockKey, ++IN BOOLEAN CheckForReadOperation, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoRead( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN BOOLEAN Wait, ++IN ULONG LockKey, ++OUT PVOID Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoWrite( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN BOOLEAN Wait, ++IN ULONG LockKey, ++OUT PVOID Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoQueryBasicInfo( ++IN PFILE_OBJECT FileObject, ++IN BOOLEAN Wait, ++OUT PFILE_BASIC_INFORMATION Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoQueryStdInfo( ++IN PFILE_OBJECT FileObject, ++IN BOOLEAN Wait, ++OUT PFILE_STANDARD_INFORMATION Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoLock( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN PLARGE_INTEGER Length, ++PEPROCESS ProcessId, ++ULONG Key, ++BOOLEAN FailImmediately, ++BOOLEAN ExclusiveLock, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoUnlockSingle( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN PLARGE_INTEGER Length, ++PEPROCESS ProcessId, ++ULONG Key, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoUnlockAll( ++IN PFILE_OBJECT FileObject, ++PEPROCESS ProcessId, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoUnlockAllByKey( ++IN PFILE_OBJECT FileObject, ++PEPROCESS ProcessId, ++ULONG Key, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern void STDCALL Ext2FastIoAcqCreateSec( ++IN PFILE_OBJECT FileObject); ++ ++extern void STDCALL Ext2FastIoRelCreateSec( ++IN PFILE_OBJECT FileObject); ++ ++extern BOOLEAN STDCALL Ext2AcqLazyWrite( ++IN PVOID Context, ++IN BOOLEAN Wait); ++ ++extern void STDCALL Ext2RelLazyWrite( ++IN PVOID Context); ++ ++extern BOOLEAN STDCALL Ext2AcqReadAhead( ++IN PVOID Context, ++IN BOOLEAN Wait); ++ ++extern void STDCALL Ext2RelReadAhead( ++IN PVOID Context); ++ ++// the remaining are only valid under NT Version 4.0 and later ++#if(_WIN32_WINNT >= 0x0400) ++ ++extern BOOLEAN STDCALL Ext2FastIoQueryNetInfo( ++IN PFILE_OBJECT FileObject, ++IN BOOLEAN Wait, ++OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoMdlRead( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN ULONG LockKey, ++OUT PMDL *MdlChain, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoMdlReadComplete( ++IN PFILE_OBJECT FileObject, ++OUT PMDL MdlChain, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoPrepareMdlWrite( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN ULONG LockKey, ++OUT PMDL *MdlChain, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern BOOLEAN STDCALL Ext2FastIoMdlWriteComplete( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++OUT PMDL MdlChain, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern NTSTATUS STDCALL Ext2FastIoAcqModWrite( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER EndingOffset, ++OUT PERESOURCE *ResourceToRelease, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern NTSTATUS STDCALL Ext2FastIoRelModWrite( ++IN PFILE_OBJECT FileObject, ++IN PERESOURCE ResourceToRelease, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern NTSTATUS STDCALL Ext2FastIoAcqCcFlush( ++IN PFILE_OBJECT FileObject, ++IN PDEVICE_OBJECT DeviceObject); ++ ++extern NTSTATUS STDCALL Ext2FastIoRelCcFlush( ++IN PFILE_OBJECT FileObject, ++IN PDEVICE_OBJECT DeviceObject); ++ ++#endif // (_WIN32_WINNT >= 0x0400) ++ ++/************************************************************************* ++* Prototypes for the file DiskIO.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2ReadLogicalBlocks( ++PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object ++VOID *Buffer, // The Buffer that takes the data read in ++LARGE_INTEGER StartLogicalBlock, // The logical block from which reading is to start ++unsigned int NoOfLogicalBlocks); // The no. of logical blocks to be read ++ ++extern NTSTATUS STDCALL Ext2ReadPhysicalBlocks( ++ PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object ++ VOID *Buffer, // The Buffer that takes the data read in ++ LARGE_INTEGER StartBlock, // The Physical block from which reading is to start ++ unsigned int NoOfBlocks); // The no. of Physical blocks to be read ++ ++/************************************************************************* ++* Prototypes for the file metadata.c ++*************************************************************************/ ++ ++extern void STDCALL Ext2InitializeFCBInodeInfo ( ++ PtrExt2FCB PtrFCB ); ++ ++extern NTSTATUS STDCALL Ext2ReadInode( ++ PtrExt2VCB PtrVcb, // the Volume Control Block ++ uint32 InodeNo, // The Inode no ++ PEXT2_INODE PtrInode ); // The Inode Buffer ++ ++extern NTSTATUS STDCALL Ext2WriteInode( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVcb, // the Volume Control Block ++ uint32 InodeNo, // The Inode no ++ PEXT2_INODE PtrInode // The Inode Buffer ++ ); ++ ++extern ULONG STDCALL Ext2AllocInode( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ ULONG ParentINodeNo ); ++ ++extern BOOLEAN STDCALL Ext2DeallocInode( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ ULONG INodeNo ); ++ ++extern BOOLEAN STDCALL Ext2MakeNewDirectoryEntry( ++ PtrExt2IrpContext PtrIrpContext, // The Irp context ++ PtrExt2FCB PtrParentFCB, // Parent Folder FCB ++ PFILE_OBJECT PtrFileObject, // Parent Folder Object ++ PUNICODE_STRING PtrName, // New entry's name ++ ULONG Type, // The type of the new entry ++ ULONG NewInodeNo); // The inode no of the new entry... ++ ++extern BOOLEAN STDCALL Ext2FreeDirectoryEntry( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2FCB PtrParentFCB, ++ PUNICODE_STRING PtrName); ++ ++extern BOOLEAN STDCALL Ext2AddBlockToFile( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ PtrExt2FCB PtrFCB, ++ PFILE_OBJECT PtrFileObject, ++ BOOLEAN UpdateFileSize); ++ ++extern BOOLEAN STDCALL Ext2ReleaseDataBlocks( ++ PtrExt2FCB PtrFCB, ++ PtrExt2IrpContext PtrIrpContext); ++ ++extern BOOLEAN STDCALL Ext2TruncateFileAllocationSize( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2FCB PtrFCB, ++ PFILE_OBJECT PtrFileObject, ++ PLARGE_INTEGER PtrAllocationSize ); ++ ++extern ULONG STDCALL Ext2AllocBlock( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ ULONG Count); ++ ++extern BOOLEAN STDCALL Ext2DeallocBlock( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ ULONG BlockNo); ++ ++extern BOOLEAN STDCALL Ext2UpdateFileSize( ++ PtrExt2IrpContext PtrIrpContext, ++ PFILE_OBJECT PtrFileObject, ++ PtrExt2FCB PtrFCB); ++ ++ ++extern BOOLEAN STDCALL Ext2DeleteFile( ++ PtrExt2FCB PtrFCB, ++ PtrExt2IrpContext PtrIrpContext); ++ ++extern BOOLEAN STDCALL Ext2IsDirectoryEmpty( ++ PtrExt2FCB PtrFCB, ++ PtrExt2CCB PtrCCB, ++ PtrExt2IrpContext PtrIrpContext); ++ ++extern NTSTATUS STDCALL Ext2RenameOrLinkFile( ++ PtrExt2FCB PtrSourceFCB, ++ PFILE_OBJECT PtrSourceFileObject, ++ PtrExt2IrpContext PtrIrpContext, ++ PIRP PtrIrp, ++ PFILE_RENAME_INFORMATION PtrRenameInfo); ++/************************************************************************* ++* Prototypes for the file io.c ++*************************************************************************/ ++extern NTSTATUS STDCALL Ext2PassDownSingleReadWriteIRP( ++ PtrExt2IrpContext PtrIrpContext, ++ PIRP PtrIrp, ++ PtrExt2VCB PtrVCB, ++ LARGE_INTEGER ByteOffset, ++ uint32 ReadWriteLength, ++ BOOLEAN SynchronousIo); ++ ++extern NTSTATUS STDCALL Ext2PassDownMultiReadWriteIRP( ++ PEXT2_IO_RUN PtrIoRuns, ++ UINT Count, ++ ULONG TotalReadWriteLength, ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2FCB PtrFCB, ++ BOOLEAN SynchronousIo); ++ ++extern NTSTATUS STDCALL Ext2SingleSyncCompletionRoutine( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp, ++ IN PVOID Contxt ++ ); ++ ++extern NTSTATUS STDCALL Ext2SingleAsyncCompletionRoutine ( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp, ++ IN PVOID Contxt ++ ); ++ ++extern NTSTATUS STDCALL Ext2MultiSyncCompletionRoutine( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp, ++ IN PVOID Contxt); ++ ++extern NTSTATUS STDCALL Ext2MultiAsyncCompletionRoutine( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp, ++ IN PVOID Contxt); ++ ++#endif // _EXT2_PROTOS_H_ diff --cc reactos/drivers/filesystems/ext2/inc/resource.h index 00000000000,00000000000..9c490bf5b6c new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/resource.h @@@ -1,0 -1,0 +1,16 @@@ ++//{{NO_DEPENDENCIES}} ++// Microsoft Developer Studio generated include file. ++// Used by D:\Work\VC\Drivers\ext2FSD\src\ext2.rc ++// ++ ++// Next default values for new objects ++// ++#ifdef APSTUDIO_INVOKED ++#ifndef APSTUDIO_READONLY_SYMBOLS ++#define _APS_NO_MFC 1 ++#define _APS_NEXT_RESOURCE_VALUE 102 ++#define _APS_NEXT_COMMAND_VALUE 40001 ++#define _APS_NEXT_CONTROL_VALUE 1000 ++#define _APS_NEXT_SYMED_VALUE 101 ++#endif ++#endif diff --cc reactos/drivers/filesystems/ext2/inc/struct.h index 00000000000,00000000000..1b4e83d6516 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/inc/struct.h @@@ -1,0 -1,0 +1,674 @@@ ++/************************************************************************* ++* ++* File: struct.h ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* This file contains structure definitions for the sample file system ++* driver. Note that all structures are prefixed with the letters ++* "Ext2". The structures are all aligned using normal alignment ++* used by the compiler (typically quad-word aligned). ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#ifndef _EXT2_STRUCTURES_H_ ++#define _EXT2_STRUCTURES_H_ ++ ++/************************************************************************** ++ some useful definitions ++**************************************************************************/ ++#ifdef _CPU_X86_ ++typedef char int8; ++typedef short int16; ++typedef int int32; ++ ++typedef unsigned char uint8; ++typedef unsigned short uint16; ++typedef unsigned int uint32; ++ ++typedef PVOID PBCB; ++ ++// we will use the LARGE_INTEGER structure as defined by NT ++ ++#else // Please define appropriate types here ++ ++!!!! You must define your types here for compilation to proceed !!!! ++ ++#endif // if _CPU_X86_ ++ ++/************************************************************************** ++ some empty typedefs defined here so we can reference them easily ++**************************************************************************/ ++struct _Ext2Identifier; ++struct _Ext2ObjectName; ++struct _Ext2ContextControlBlock; ++struct _Ext2NTRequiredFCB; ++struct _Ext2DiskDependentFCB; ++struct _Ext2FileControlBlock; ++struct _Ext2FileByteLocks; ++struct _Ext2VolumeControlBlock; ++struct _Ext2IrpContext; ++struct _Ext2Data; ++ ++/************************************************************************** ++ each structure has a unique "node type" or signature associated with it ++**************************************************************************/ ++#define EXT2_NODE_TYPE_OBJECT_NAME (0xfdecba01) ++#define EXT2_NODE_TYPE_CCB (0xfdecba02) ++#define EXT2_NODE_TYPE_FCB (0xfdecba03) ++#define EXT2_NODE_TYPE_LOCKS (0xfdecba04) ++#define EXT2_NODE_TYPE_VCB (0xfdecba05) ++#define EXT2_NODE_TYPE_IRP_CONTEXT (0xfdecba06) ++#define EXT2_NODE_TYPE_GLOBAL_DATA (0xfdecba07) ++#define EXT2_NODE_TYPE_IO_CONTEXT (0xfdecba08) ++#define EXT2_NODE_TYPE_SAVED_BCB (0xfdecba09) ++#define EXT2_NODE_TYPE_FREED (0x10101010) ++#define EXT2_NODE_TYPE_INVALID (0x10101010) ++ ++/************************************************************************** ++ every structure has a node type, and a node size associated with it. ++ The node type serves as a signature field. The size is used for ++ consistency checking ... ++**************************************************************************/ ++typedef struct _Ext2Identifier { ++ uint32 NodeType; // a 32 bit identifier for the structure ++ uint32 NodeSize; // computed as sizeof(structure) ++} Ext2Identifier, *PtrExt2Identifier; ++ ++/************************************************************************** ++ Structures for byte-range lock support. ++**************************************************************************/ ++typedef struct Ext2FileLockAnchor { ++ LIST_ENTRY GrantedFileLockList; ++ LIST_ENTRY PendingFileLockList; ++} Ext2FileLockAnchor, *PtrExt2FileLockAnchor; ++ ++typedef struct Ext2FileLockInfo { ++ Ext2Identifier NodeIdentifier; ++ uint32 FileLockFlags; ++ PVOID OwningProcess; ++ LARGE_INTEGER StartingOffset; ++ LARGE_INTEGER Length; ++ LARGE_INTEGER EndingOffset; ++ ULONG Key; ++ BOOLEAN ExclusiveLock; ++ PIRP PendingIRP; ++ LIST_ENTRY NextFileLockEntry; ++} Ext2FileLockInfo, *PtrExt2FileLockInfo; ++ ++#define EXT2_BYTE_LOCK_NOT_FROM_ZONE (0x80000000) ++#define EXT2_BYTE_LOCK_IS_PENDING (0x00000001) ++ ++/************************************************************************** ++ Every open on-disk object must have a name associated with it ++ This name has two components: ++ (a) the path-name (prefix) that leads to this on-disk object ++ (b) the name of the object itself ++ Note that with multiply linked objects, a single object might be ++ associated with more than one name structure. ++ This sample FSD does not correctly support multiply linked objects. ++ ++ This structure must be quad-word aligned because it is zone allocated. ++**************************************************************************/ ++typedef struct _Ext2ObjectName { ++ Ext2Identifier NodeIdentifier; ++ uint32 ObjectNameFlags; ++ // an absolute pathname of the object is stored below ++ UNICODE_STRING ObjectName; ++} Ext2ObjectName, *PtrExt2ObjectName; ++ ++#define EXT2_OB_NAME_NOT_FROM_ZONE (0x80000000) ++ ++/************************************************************************** ++ Each file open instance is represented by a context control block. ++ For each successful create/open request; a file object and a CCB will ++ be created. ++ For open operations performed internally by the FSD, there may not ++ exist file objects; but a CCB will definitely be created. ++ ++ This structure must be quad-word aligned because it is zone allocated. ++**************************************************************************/ ++typedef struct _Ext2ContextControlBlock { ++ Ext2Identifier NodeIdentifier; ++ // ptr to the associated FCB ++ struct _Ext2FileControlBlock *PtrFCB; ++ // all CCB structures for a FCB are linked together ++ LIST_ENTRY NextCCB; ++ // each CCB is associated with a file object ++ PFILE_OBJECT PtrFileObject; ++ // flags (see below) associated with this CCB ++ uint32 CCBFlags; ++ // current byte offset is required sometimes ++ LARGE_INTEGER CurrentByteOffset; ++ // if this CCB represents a directory object open, we may ++ // need to maintain a search pattern ++ ++ // PSTRING DirectorySearchPattern; ++ UNICODE_STRING DirectorySearchPattern; ++ ++ // The full path name for the file... ++ UNICODE_STRING AbsolutePathName; ++ ++ // Rename/Link Target file name ++ // Used only in a Rename/Link operation ++ UNICODE_STRING RenameLinkTargetFileName; ++ ++ // we must maintain user specified file time values ++ uint32 UserSpecifiedTime; ++ ++ ++} Ext2CCB, *PtrExt2CCB; ++ ++ ++/************************************************************************** ++ the following CCBFlags values are relevant. These flag ++ values are bit fields; therefore we can test whether ++ a bit position is set (1) or not set (0). ++**************************************************************************/ ++ ++// some on-disk file/directories are opened by EXT2 itself ++// as opposed to being opened on behalf of a user process ++#define EXT2_CCB_OPENED_BY_EXT2 (0x00000001) ++// the file object specified synchronous access at create/open time. ++// this implies that EXT2 must maintain the current byte offset ++#define EXT2_CCB_OPENED_FOR_SYNC_ACCESS (0x00000002) ++// file object specified sequential access for this file ++#define EXT2_CCB_OPENED_FOR_SEQ_ACCESS (0x00000004) ++// the CCB has had an IRP_MJ_CLEANUP issued on it. we must ++// no longer allow the file object / CCB to be used in I/O requests. ++#define EXT2_CCB_CLEANED (0x00000008) ++// if we were invoked via the fast i/o path to perform file i/o; ++// we should set the CCB access/modification time at cleanup ++#define EXT2_CCB_ACCESSED (0x00000010) ++#define EXT2_CCB_MODIFIED (0x00000020) ++// if an application process set the file date time, we must ++// honor that request and *not* overwrite the values at cleanup ++#define EXT2_CCB_ACCESS_TIME_SET (0x00000040) ++#define EXT2_CCB_MODIFY_TIME_SET (0x00000080) ++#define EXT2_CCB_CREATE_TIME_SET (0x00000100) ++ ++#define EXT2_CCB_NOT_FROM_ZONE (0x80000000) ++ ++// this CCB was allocated for a "volume open" operation ++#define EXT2_CCB_VOLUME_OPEN (0x00000100) ++ ++/************************************************************************** ++ each open file/directory/volume is represented by a file control block. ++ NOTE: Currently, EXT2 does not handle multiply linked files correctly. ++ In your FSD implementation, you must be careful about handling ++ such on-disk files correctly i.e. a single (unique) FCB must ++ represent an on-disk file/directory regardless of the path used ++ to access the on-disk object. ++ With the current EXT2 implementation, an on-disk file object ++ with more than a single (hard) link will be treated incorrectly! ++ ++ Each FCB can logically be divided into two: ++ (a) a structure that must have a field of type FSRTL_COMMON_FCB_HEADER ++ as the first field in the structure. ++ This portion should also contain other structures/resources required ++ by the NT Cache Manager ++ We will call this structure the "NT Required" FCB. Note that this ++ portion of the FCB must be allocated from non-paged pool. ++ (b) the remainder of the FCB is dependent upon the particular FSD ++ requirements. ++ This portion of the FCB could possibly be allocated from paged ++ memory, though in the sample FSD, it will always be allocated ++ from non-paged pool. ++ ++ FCB structures are protected by the MainResource as well as the ++ PagingIoResource. Of course, if your FSD implementation requires ++ it, you can associate other syncronization structures with the ++ FCB. ++ ++ This structure must be quad-word aligned because it is zone allocated. ++**************************************************************************/ ++typedef struct _Ext2NTRequiredFCB ++{ ++ FSRTL_COMMON_FCB_HEADER CommonFCBHeader; ++ SECTION_OBJECT_POINTERS SectionObject; ++ ERESOURCE MainResource; ++ ERESOURCE PagingIoResource; ++} Ext2NTRequiredFCB, *PtrExt2NTRequiredFCB; ++ ++typedef struct _Ext2DiskDependentFCB ++{ ++ // although the sample FSD does not maintain on-disk data structures, ++ // this structure serves as a reminder of the logical separation that ++ // your FSD can maintain between the disk dependent and the disk ++ // independent portions of the FCB. ++ uint16 DummyField; // placeholder ++} Ext2DiskDependentFCB, *PtrExt2DiskDependentFCB; ++ ++typedef struct _Ext2FileControlBlock ++{ ++ Ext2Identifier NodeIdentifier; ++ // we will go ahead and embed the "NT Required FCB" right here. ++ // Note though that it is just as acceptable to simply allocate ++ // memory separately for the other half of the FCB and store a ++ // pointer to the "NT Required" portion here instead of embedding ++ // it ... ++ Ext2NTRequiredFCB NTRequiredFCB; ++ // the disk dependent portion of the FCB is embedded right here ++ Ext2DiskDependentFCB DiskDependentFCB; ++ // this FCB belongs to some mounted logical volume ++ struct _Ext2VolumeControlBlock *PtrVCB; ++ // to be able to access all open file(s) for a volume, we will ++ // link all FCB structures for a logical volume together ++ LIST_ENTRY NextFCB; ++ ++ // to be used if this FCB is on the Closable FCB List... ++ struct _ClosableFCBs ++ { ++ LIST_ENTRY ClosableFCBList; ++ BOOLEAN OnClosableFCBList; ++ }ClosableFCBs; ++ ++ // some state information for the FCB is maintained using the ++ // flags field ++ uint32 FCBFlags; ++ // all CCB's for this particular FCB are linked off the following ++ // list head. ++ LIST_ENTRY CCBListHead; ++ // NT requires that a file system maintain and honor the various ++ // SHARE_ACCESS modes ... ++ SHARE_ACCESS FCBShareAccess; ++ // to identify the lazy writer thread(s) we will grab and store ++ // the thread id here when a request to acquire resource(s) ++ // arrives .. ++ uint32 LazyWriterThreadID; ++ // whenever a file stream has a create/open operation performed, ++ // the Reference count below is incremented AND the OpenHandle count ++ // below is also incremented. ++ // When an IRP_MJ_CLEANUP is received, the OpenHandle count below ++ // is decremented. ++ // When an IRP_MJ_CLOSE is received, the Reference count below is ++ // decremented. ++ // When the Reference count goes down to zero, the FCB can be de-allocated. ++ // Note that a zero Reference count implies a zero OpenHandle count. ++ // This invariant must always hold true ... (if it is really an invariant, ++ // shoudn't the previous statement be redundant ... hmmm!!!) ++ LONG ReferenceCount; ++ LONG OpenHandleCount; ++ // for the sample fsd, there exists a 1-1 correspondence between an ++ // object name structure and a FCB ++ PtrExt2ObjectName FCBName; ++ // we will maintain some time information here to make our life easier ++ LARGE_INTEGER CreationTime; ++ LARGE_INTEGER LastAccessTime; ++ LARGE_INTEGER LastWriteTime; ++ // Byte-range file lock support (we roll our own) ++ Ext2FileLockAnchor FCBByteRangeLock; ++ // The OPLOCK support package requires the following structure ++ OPLOCK FCBOplock; ++ ++ // The I-Node no of this file / folder ++ ULONG INodeNo; ++ ULONG ParentINodeNo; ++ // Pointers to blocks ++ uint32 IBlock[EXT2_N_BLOCKS]; ++ ++ USHORT LinkCount; ++ union _DCBFCB ++ { ++ struct ++ { ++ PFILE_OBJECT PtrDirFileObject; ++ } Dcb; ++ ++ struct _FCB ++ { ++ PFILE_OBJECT PtrDirFileObject; ++ // FCB specific stuff go here... ++ } Fcb; ++ ++ }DcbFcb; ++ ++} Ext2FCB, *PtrExt2FCB, Ext2DCB, *PtrExt2DCB; ++ ++/************************************************************************** ++ the following FCBFlags values are relevant. These flag ++ values are bit fields; therefore we can test whether ++ a bit position is set (1) or not set (0). ++**************************************************************************/ ++#define EXT2_FCB_IN_INIT (0x00000001) ++#define EXT2_FCB_IN_TEARDOWN (0x00000002) ++#define EXT2_FCB_PAGE_FILE (0x00000004) ++#define EXT2_FCB_DIRECTORY (0x00000008) ++#define EXT2_FCB_ROOT_DIRECTORY (0x00000018) ++#define EXT2_FCB_WRITE_THROUGH (0x00000020) ++#define EXT2_FCB_MAPPED (0x00000040) ++#define EXT2_FCB_FAST_IO_READ_IN_PROGESS (0x00000080) ++#define EXT2_FCB_FAST_IO_WRITE_IN_PROGESS (0x00000100) ++#define EXT2_FCB_DELETE_ON_CLOSE (0x00000200) ++#define EXT2_FCB_MODIFIED (0x00000400) ++#define EXT2_FCB_ACCESSED (0x00000800) ++#define EXT2_FCB_READ_ONLY (0x00001000) ++ ++#define EXT2_INITIALIZED_MAIN_RESOURCE (0x00002000) ++#define EXT2_INITIALIZED_PAGING_IO_RESOURCE (0x00004000) ++#define EXT2_FCB_BLOCKS_INITIALIZED (0x00008000) ++#define EXT2_FCB_SPECIAL_FILE (0x00010000) ++#define EXT2_FCB_HIDDEN_FILE (0x00020000) ++#define EXT2_FCB_NOT_FROM_ZONE (0x80000000) ++ ++ ++typedef struct _GroupDescriptors ++{ ++ uint32 InodeTablesBlock; /* Inodes table block => bg_inode_table */ ++ uint32 InodeBitmapBlock; /* Inodes bitmap block => bg_inode_bitmap */ ++ uint32 BlockBitmapBlock; /* Blocks bitmap block => bg_block_bitmap */ ++ uint32 FreeBlocksCount; ++ uint32 FreeInodesCount; ++}Ext2GroupDescriptors, *PtrExt2GroupDescriptors; ++ ++ ++ ++/************************************************************************** ++ A logical volume is represented using the following structure. ++ This structure is allocated as part of the device extension ++ for a device object that this sample FSD will create, to represent ++ the mounted logical volume. ++ ++ NOTE: If you were to extend this sample FSD to be a "real" FSD, ++ you would be worried about allocated clusters/sectiors, ++ bitmaps providing such information for the mounted volume, ++ dirty/modified clusters/sectiors etc. ++ This sample FSD does not maintain such information in the ++ in-memory VCB, though you may wish to consider it. ++**************************************************************************/ ++typedef struct _Ext2VolumeControlBlock ++{ ++ Ext2Identifier NodeIdentifier; ++ ++ // Required to use the Cache Manager. ++ FSRTL_COMMON_FCB_HEADER CommonVCBHeader; ++ SECTION_OBJECT_POINTERS SectionObject; ++ // a resource to protect the fields contained within the VCB ++ ERESOURCE VCBResource; ++ ++ // a resource to synchronise paging io ++ ERESOURCE PagingIoResource; ++ ++ // Pointer to a stream file object created for the volume information ++ // to be more easily read from secondary storage (with the support of ++ // the NT Cache Manager). ++ PFILE_OBJECT PtrStreamFileObject; ++ ++ // each VCB is accessible off a global linked list ++ LIST_ENTRY NextVCB; ++ ++ // each VCB points to a VPB structure created by the NT I/O Manager ++ PVPB PtrVPB; ++ ++ // a set of flags that might mean something useful ++ uint32 VCBFlags; ++ ++ // A count of the number of open files/directories ++ // As long as the count is != 0, the volume cannot ++ // be dismounted or locked. ++ uint32 VCBOpenCount; ++ ++ // a global list of all FCB structures associated with the VCB ++ LIST_ENTRY FCBListHead; ++ ++ // ++ // a list of FCBs created at the FSD's initiative... ++ // These FCBs have a reference count of 0 ++ // This list should never be allowed to cross a limit... ++ // ++ struct Ext2ClosableFCB ++ { ++ LIST_ENTRY ClosableFCBListHead; ++ ULONG Count; ++ }ClosableFCBs; ++ // we will maintain a global list of IRP's that are pending ++ // because of a directory notify request. ++ LIST_ENTRY NextNotifyIRP; ++ // the above list is protected only by the mutex declared below ++ KMUTEX NotifyIRPMutex; ++ // for each mounted volume, we create a device object. Here then ++ // is a back pointer to that device object ++ PDEVICE_OBJECT VCBDeviceObject; ++ // We also retain a pointer to the physical device object on which we ++ // have mounted ourselves. The I/O Manager passes us a pointer to this ++ // device object when requesting a mount operation. ++ PDEVICE_OBJECT TargetDeviceObject; ++ // the volume structure contains a pointer to the root directory FCB ++ PtrExt2FCB PtrRootDirectoryFCB; ++ // the complete name of the user visible drive letter we serve ++ uint8 *PtrVolumePath; ++ // For volume open operations, we do not create a FCB (we use the VCB ++ // directly instead). Therefore, all CCB structures for the volume ++ // open operation are linked directly off the VCB ++ LIST_ENTRY VolumeOpenListHead; ++ ++ ++ // Volume information ++ ULONG BlocksCount; ++ ULONG InodesCount; ++ ULONG ReservedBlocksCount; ++ ULONG FreeBlocksCount; ++ ULONG FreeInodesCount; ++ ULONG LogBlockSize; // Block size = 1024 << LogBlockSize ++ ++ // Group Information Saved up in the VCB... ++ PtrExt2GroupDescriptors PtrGroupDescriptors; ++ ULONG NoOfGroups; ++ ++ uint32 InodesPerGroup; ++ uint32 BlocksPerGroup; ++ ++} Ext2VCB, *PtrExt2VCB; ++ ++// some valid flags for the VCB ++#define EXT2_VCB_FLAGS_VOLUME_MOUNTED (0x00000001) ++#define EXT2_VCB_FLAGS_VOLUME_LOCKED (0x00000002) ++#define EXT2_VCB_FLAGS_BEING_DISMOUNTED (0x00000004) ++#define EXT2_VCB_FLAGS_SHUTDOWN (0x00000008) ++#define EXT2_VCB_FLAGS_VOLUME_READ_ONLY (0x00000010) ++ ++#define EXT2_VCB_FLAGS_VCB_INITIALIZED (0x00000020) ++ ++typedef struct _EXT2_IO_CONTEXT ++{ ++ Ext2Identifier NodeIdentifier; ++ ULONG ReadWriteLength; ++ LONG Count; ++ PIRP PtrMasterIrp; ++ PKEVENT PtrSyncEvent; ++ ++} EXT2_IO_CONTEXT, *PEXT2_IO_CONTEXT; ++ ++ ++typedef struct _Ext2SavedBCBs ++{ ++ Ext2Identifier NodeIdentifier; ++ PBCB PtrBCB; ++ LIST_ENTRY SavedBCBsListEntry; ++ ++} EXT2_SAVED_BCBS, *PEXT2_SAVED_BCBS; ++ ++ ++/************************************************************************** ++ The IRP context encapsulates the current request. This structure is ++ used in the "common" dispatch routines invoked either directly in ++ the context of the original requestor, or indirectly in the context ++ of a system worker thread. ++**************************************************************************/ ++typedef struct _Ext2IrpContext ++{ ++ Ext2Identifier NodeIdentifier; ++ uint32 IrpContextFlags; ++ // copied from the IRP ++ uint8 MajorFunction; ++ // copied from the IRP ++ uint8 MinorFunction; ++ ++ // to queue this IRP for asynchronous processing ++ WORK_QUEUE_ITEM WorkQueueItem; ++ // the IRP for which this context structure was created ++ PIRP Irp; ++ // the target of the request (obtained from the IRP) ++ PDEVICE_OBJECT TargetDeviceObject; ++ // if an exception occurs, we will store the code here ++ NTSTATUS SavedExceptionCode; ++ ++ // This list entry is used if asnchronous processing is required... ++ LIST_ENTRY ThreadQueueListEntry; ++ ++ // This list entry is used if BCBs are to be saved and then flushed... ++ // Could have been put somewhere else... ++ LIST_ENTRY SavedBCBsListHead; ++ ULONG SavedCount; ++ ++} Ext2IrpContext, *PtrExt2IrpContext; ++ ++#define EXT2_IRP_CONTEXT_CAN_BLOCK (0x00000001) ++#define EXT2_IRP_CONTEXT_WRITE_THROUGH (0x00000002) ++#define EXT2_IRP_CONTEXT_EXCEPTION (0x00000004) ++#define EXT2_IRP_CONTEXT_DEFERRED_WRITE (0x00000008) ++#define EXT2_IRP_CONTEXT_ASYNC_PROCESSING (0x00000010) ++#define EXT2_IRP_CONTEXT_NOT_TOP_LEVEL (0x00000020) ++ ++#define EXT2_IRP_CONTEXT_NOT_FROM_ZONE (0x80000000) ++ ++typedef struct _Ext2ThreadQueue ++{ ++ HANDLE QueueHandlerThread; ++ ++ LIST_ENTRY ThreadQueueListHead; // This holds the Contexts ++ // that are to be scheduled ++ KSPIN_LOCK SpinLock; // To synchronize access to ++ // the list ++ KEVENT QueueEvent; // The Worker thread queue ++ // package waits on this event ++} Ext2ThreadQueue; ++ ++/************************************************************************** ++ we will store all of our global variables in one structure. ++ Global variables are not specific to any mounted volume BUT ++ by definition are required for successful operation of the ++ FSD implementation. ++**************************************************************************/ ++typedef struct _Ext2Data ++{ ++ Ext2Identifier NodeIdentifier; ++ // the fields in this list are protected by the following resource ++ ERESOURCE GlobalDataResource; ++ // each driver has a driver object created for it by the NT I/O Mgr. ++ // we are no exception to this rule. ++ PDRIVER_OBJECT Ext2DriverObject; ++ // we will create a device object for our FSD as well ... ++ // Although not really required, it helps if a helper application ++ // writen by us wishes to send us control information via ++ // IOCTL requests ... ++ PDEVICE_OBJECT Ext2DeviceObject; ++ // we will keep a list of all logical volumes for our sample FSD ++ LIST_ENTRY NextVCB; ++ // the NT Cache Manager, the I/O Manager and we will conspire ++ // to bypass IRP usage using the function pointers contained ++ // in the following structure ++ FAST_IO_DISPATCH Ext2FastIoDispatch; ++ // The NT Cache Manager uses the following call backs to ensure ++ // correct locking hierarchy is maintained ++ CACHE_MANAGER_CALLBACKS CacheMgrCallBacks; ++ // structures allocated from a zone need some fields here. Note ++ // that under version 4.0, it might be better to use lookaside ++ // lists ++ KSPIN_LOCK ZoneAllocationSpinLock; ++ ZONE_HEADER ObjectNameZoneHeader; ++ ZONE_HEADER CCBZoneHeader; ++ ZONE_HEADER FCBZoneHeader; ++ ZONE_HEADER ByteLockZoneHeader; ++ ZONE_HEADER IrpContextZoneHeader; ++ void *ObjectNameZone; ++ void *CCBZone; ++ void *FCBZone; ++ void *ByteLockZone; ++ void *IrpContextZone; ++ ++ // currently, there is a single default zone size value used for ++ // all zones. This should ideally be changed by you to be 1 per ++ // type of zone (e.g. a default size for the FCB zone might be ++ // different from the default size for the ByteLock zone). ++ ++ // Of course, you will need to use different values (min/max) ++ // for lookaside lists (if you decide to use them instead) ++ uint32 DefaultZoneSizeInNumStructs; ++ ++ // some state information is maintained in the flags field ++ uint32 Ext2Flags; ++ ++ // Handle returned by the MUP is stored here. ++ HANDLE MupHandle; ++ ++ // Time difference ++ LARGE_INTEGER TimeDiff; ++ ++ // The Worker Thread package uses this structure... ++ Ext2ThreadQueue ThreadQueue; ++ ++}Ext2Data, *PtrExt2Data; ++ ++// valid flag values for the global data structure ++#define EXT2_DATA_FLAGS_RESOURCE_INITIALIZED (0x00000001) ++#define EXT2_DATA_FLAGS_ZONES_INITIALIZED (0x00000002) ++ ++// a default size of the number of pages of non-paged pool allocated ++// for each of the zones ... ++ ++// Note that the values are absolutely arbitrary, the only information ++// worth using from the values themselves is that they increase for ++// larger systems (i.e. systems with more memory) ++#define EXT2_DEFAULT_ZONE_SIZE_SMALL_SYSTEM (0x4) ++#define EXT2_DEFAULT_ZONE_SIZE_MEDIUM_SYSTEM (0x8) ++#define EXT2_DEFAULT_ZONE_SIZE_LARGE_SYSTEM (0xc) ++ ++// another simplistic (brain dead ? :-) method used is to simply double ++// the values for a "server" machine ++ ++// So, for all you guys who "modified" the registry ;-) to change the ++// wkstation into a server, tough luck ! ++#define EXT2_NTAS_MULTIPLE (0x2) ++ ++/*************************************************************************** ++The following locking hierarchy is maintained in this sample filesystem ++driver: ++ ++(a) the global structure resource can be acquired at any time. However, ++ it is an "end resource" i.e. once acquired, no other resource can ++ be obtained until the global structure resource is released. ++(b) the logical volume resource must be acquired (if required) before ++ any of the other resources are acquired. ++(c) a file control block can be acquired next (if required). If two ++ FCB structures need to be acquired, the FCB "higher" in the directory ++ tree must be acquired first. ++ For a FCB, the "main resource" must be acquired first before a ++ "paging i/o" resource is acquired. ++ ++Whenever a file is opened, the logical volume structure is referenced. ++This ensures that the volume cannot be dismounted while any file is open. ++ ++***************************************************************************/ ++ ++typedef struct _IO_RUN ++{ ++ UINT LogicalBlock; ++ UINT StartOffset; ++ UINT EndOffset; ++ PIRP PtrAssociatedIrp; ++ ++} EXT2_IO_RUN, *PEXT2_IO_RUN; ++ ++typedef struct _SIBlocks ++{ ++ PBCB PtrBCB; ++ ULONG * PtrSIBlocks; ++} EXT2_SIBLOCKS, *PEXT2_SIBLOCKS; ++ ++#endif // has this file been included? ++ diff --cc reactos/drivers/filesystems/ext2/src/DiskIO.c index 00000000000,00000000000..81ca894f8e4 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/DiskIO.c @@@ -1,0 -1,0 +1,215 @@@ ++/************************************************************************* ++* ++* File: DiskIO.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Should contain code to handle Disk IO. ++* ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++#define EXT2_BUG_CHECK_ID EXT2_FILE_DISK_IO ++ ++#define DEBUG_LEVEL ( DEBUG_TRACE_DISKIO ) ++ ++ ++/************************************************************************* ++* ++* Function: Ext2ReadLogicalBlocks() ++* ++* Description: ++* The higherlevel functions will use this to read in logical blocks ++* This function deals with the logical to physical block translation ++* ++* LogicalBlock - This is a 1 based index. ++* That is, the first block is Block 1 ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: The Status of the Read IO ++* ++*************************************************************************/ ++NTSTATUS Ext2ReadLogicalBlocks ( ++ PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object ++ VOID *Buffer, // The Buffer that takes the data read in ++ LARGE_INTEGER StartLogicalBlock, // The logical block from which reading is to start ++ unsigned int NoOfLogicalBlocks // The no. of logical blocks to be read ++ ) ++{ ++ // The Status to be returned... ++ NTSTATUS Status = STATUS_SUCCESS; ++ ++ // The Device Object representing the mounted volume ++ PDEVICE_OBJECT PtrVolumeDeviceObject = NULL; ++ ++ // Volume Control Block ++ PtrExt2VCB PtrVCB = NULL; ++ ++ // Logical Block Size ++ ULONG LogicalBlockSize; ++ ++ // Physical Block Size ++ ULONG PhysicalBlockSize; ++ ++ // The starting Physical Block No... ++ LARGE_INTEGER StartPhysicalBlock; ++ ++ unsigned int NoOfPhysicalBlocks; ++ ++ ++ ++ // Done with declerations... ++ // Now for some code ;) ++ ++ // Getting the Logical and Physical Sector sizes ++ PtrVolumeDeviceObject = PtrTargetDeviceObject->Vpb->DeviceObject; ++ ASSERT( PtrVolumeDeviceObject ); ++ PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); ++ ASSERT(PtrVCB); ++ ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ PhysicalBlockSize = PtrTargetDeviceObject->SectorSize; ++ ++ NoOfPhysicalBlocks = NoOfLogicalBlocks * LogicalBlockSize / PhysicalBlockSize; ++ ++ StartPhysicalBlock.QuadPart = ( StartLogicalBlock.QuadPart ) * ++ ( LogicalBlockSize / PhysicalBlockSize ); ++ ++ Status = Ext2ReadPhysicalBlocks( PtrTargetDeviceObject, ++ Buffer, StartPhysicalBlock, NoOfPhysicalBlocks ); ++ ++ return Status; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2ReadPhysicalBlocks() ++* ++* Description: ++* The higherlevel functions will use this to read in physical blocks ++* ++* PhysicalBlock - This is a 0 based number. ++* That is, the first block is Block 0 ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: The Status of the Read IO ++* ++*************************************************************************/ ++NTSTATUS Ext2ReadPhysicalBlocks ( ++ PDEVICE_OBJECT PtrTargetDeviceObject, // the Target Device Object ++ VOID *Buffer, // The Buffer that takes the data read in ++ LARGE_INTEGER StartPhysicalBlock, // The block from which reading is to start ++ unsigned int NoOfBlocks // The no. of blocks to be read ++ ) ++{ ++ // The Status to be returned... ++ NTSTATUS Status = STATUS_SUCCESS; ++ ++ // Physical Block Size ++ ULONG PhysicalBlockSize; ++ ++ // No of bytes to read ++ ULONG NumberOfBytesToRead; ++ ++ // Synchronisation Event ++ KEVENT Event; ++ ++ // IRP ++ PIRP Irp; ++ ++ // Status Block ++ IO_STATUS_BLOCK Iosb; ++ ++ // Byte Offset ++ LARGE_INTEGER ByteOffset; ++ ++ // Done with declerations... ++ // Now for some code ;) ++ ++ // Getting the Physical Sector size ++ PhysicalBlockSize = PtrTargetDeviceObject->SectorSize; ++ ++ NumberOfBytesToRead = PhysicalBlockSize * NoOfBlocks; ++ ++ ByteOffset.QuadPart = StartPhysicalBlock.QuadPart * PhysicalBlockSize; ++ ++ try ++ { ++ // ++ // Initialize the event we're going to use ++ // ++ KeInitializeEvent( &Event, NotificationEvent, FALSE ); ++ ++ // ++ // Build the irp for the operation and also set the overrride flag ++ // ++ Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, ++ PtrTargetDeviceObject, ++ Buffer, ++ NumberOfBytesToRead, ++ &ByteOffset , ++ &Event, ++ &Iosb ); ++ ++ if ( Irp == NULL ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, " !!!! Unable to create an IRP", 0 ); ++ Status = STATUS_INSUFFICIENT_RESOURCES; ++ try_return( Status ); ++ } ++ ++ // ++ // Call the device to do the read and wait for it to finish. ++ // ++ Status = IoCallDriver( PtrTargetDeviceObject, Irp ); ++ ++ // ++ // Check if it is done already!!!! ++ // ++ if (Status == STATUS_PENDING) ++ { ++ // ++ // Read not done yet... ++ // Wait till it is... ++ // ++ (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); ++ Status = Iosb.Status; ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if (!NT_SUCCESS(Status)) ++ { ++ if( Status == STATUS_VERIFY_REQUIRED ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, " !!!! Verify Required! Failed to read disk",0 ); ++ } ++ else if (Status == STATUS_INVALID_PARAMETER) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, " !!!! Invalid Parameter! Failed to read disk",0 ); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MISC, " !!!! Failed to read disk! Status returned = %d", Status ); ++ } ++ } ++ } ++ return Status; ++} ++ ++ diff --cc reactos/drivers/filesystems/ext2/src/cleanup.c index 00000000000,00000000000..50a2ab07305 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/cleanup.c @@@ -1,0 -1,0 +1,400 @@@ ++/************************************************************************* ++* ++* File: cleanup.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Should contain code to handle the "Cleanup" dispatch entry point. ++* This file serves as a placeholder. Please update this file as part ++* of designing and implementing your FSD. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_CLEANUP ++#define DEBUG_LEVEL (DEBUG_TRACE_CLEANUP) ++ ++ ++/************************************************************************* ++* ++* Function: Ext2Cleanup() ++* ++* Description: ++* The I/O Manager will invoke this routine to handle a cleanup ++* request ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution ++* to be deferred to a worker thread context) ++* ++* Return Value: Does not matter! ++* ++*************************************************************************/ ++NTSTATUS Ext2Cleanup( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp) // I/O Request Packet ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ BOOLEAN AreWeTopLevel = FALSE; ++ ++ DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Cleanup IRP Received...", 0); ++ ++ FsRtlEnterFileSystem(); ++ ASSERT(DeviceObject); ++ ASSERT(Irp); ++ ++ // set the top level context ++ AreWeTopLevel = Ext2IsIrpTopLevel(Irp); ++ ++ try ++ { ++ ++ // get an IRP context structure and issue the request ++ PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); ++ ASSERT(PtrIrpContext); ++ ++ RC = Ext2CommonCleanup(PtrIrpContext, Irp, TRUE); ++ ++ } ++ except( Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation() ) ) ++ { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, Irp); ++ ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ if (AreWeTopLevel) ++ { ++ IoSetTopLevelIrp(NULL); ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++/************************************************************************* ++* ++* Function: Ext2CommonCleanup() ++* ++* Description: ++* The actual work is performed here. This routine may be invoked in one' ++* of the two possible contexts: ++* (a) in the context of a system worker thread ++* (b) in the context of the original caller ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: Does not matter! ++* ++*************************************************************************/ ++NTSTATUS Ext2CommonCleanup( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++BOOLEAN FirstAttempt ) ++{ ++ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PIO_STACK_LOCATION PtrIoStackLocation = NULL; ++ PFILE_OBJECT PtrFileObject = NULL; ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2VCB PtrVCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ PERESOURCE PtrResourceAcquired = NULL; ++ IO_STATUS_BLOCK LocalIoStatus; ++ ++ BOOLEAN CompleteIrp = TRUE; ++ BOOLEAN PostRequest = FALSE; ++ BOOLEAN AcquiredVCB = FALSE; ++ BOOLEAN CanWait = FALSE; ++ BOOLEAN BlockForResource; ++ int i = 1; ++ ++ try ++ { ++ // First, get a pointer to the current I/O stack location ++ PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ++ ASSERT(PtrIoStackLocation); ++ ++ PtrFileObject = PtrIoStackLocation->FileObject; ++ ASSERT(PtrFileObject); ++ ++ if( !PtrFileObject->FsContext2 ) ++ { ++ // This must be a Cleanup request received ++ // as a result of IoCreateStreamFileObject ++ // Only such a File object would have a NULL CCB ++ ++ DebugTrace( DEBUG_TRACE_MISC, " === Cleanup with NULL CCB", 0); ++ if( PtrFileObject ) ++ { ++ DebugTrace( DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); ++ } ++ try_return( RC ); ++ } ++ ++ ++ Ext2GetFCB_CCB_VCB_FromFileObject ( ++ PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); ++ ++ if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) ++ //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer ) ++ { ++ DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); ++ } ++ else ++ { ++ DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup Volume", 0); ++ } ++ ++ ++ PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); ++ ASSERT(PtrVCB); ++ ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); ++ ++ // (a) Acquiring the VCBResource Exclusively... ++ // This is done to synchronise with the close and cleanup routines... ++ BlockForResource = !FirstAttempt; ++ if( !FirstAttempt ) ++ { ++ ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire VCB Exclusively [Cleanup]", 0); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Cleanup]", 0); ++ } ++ ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); ++ } ++ ++ i = 1; ++ while( !AcquiredVCB ) ++ { ++ DebugTraceState("VCB AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); ++ if( ! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) ++ { ++ DebugTrace( DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Cleanup]", 0); ++ if( BlockForResource && i != 1000 ) ++ { ++ LARGE_INTEGER Delay; ++ Delay.QuadPart = -500 * i; ++ KeDelayExecutionThread( KernelMode, FALSE, &Delay ); ++ DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i); ++ } ++ else ++ { ++ if( i == 1000 ) ++ DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 ); ++ PostRequest = TRUE; ++ try_return( RC = STATUS_PENDING ); ++ } ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired in [Cleanup]", 0); ++ AcquiredVCB = TRUE; ++ } ++ i *= 10; ++ } ++ ++ ++ // (b) Acquire the file (FCB) exclusively ++ if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) ++ { ++ // This FCB is an FCB indeed. ;) ++ // So acquiring it exclusively... ++ // This is done to synchronise with read/write routines... ++ if( !FirstAttempt ) ++ { ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire FCB Exclusively [Cleanup]", 0); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Cleanup]", 0); ++ } ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); ++ } ++ ++ i = 1; ++ while( !PtrResourceAcquired ) ++ { ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ++ if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) ++ { ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Cleanup]", 0); ++ if( BlockForResource && i != 1000 ) ++ { ++ LARGE_INTEGER Delay; ++ Delay.QuadPart = -500 * i; ++ KeDelayExecutionThread( KernelMode, FALSE, &Delay ); ++ DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i); ++ } ++ else ++ { ++ if( i == 1000 ) ++ DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 ); ++ PostRequest = TRUE; ++ try_return( RC = STATUS_PENDING ); ++ } ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB acquired [Cleanup]", 0); ++ PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource ); ++ } ++ i *= 10; ++ } ++ ++ // (c) Flush file data to disk ++ if ( PtrFileObject->PrivateCacheMap != NULL) ++ { ++ IO_STATUS_BLOCK Status; ++ CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status ); ++ } ++ ++ // (d) Talk to the FSRTL package (if you use it) about pending oplocks. ++ // (e) Notify the FSRTL package (if you use it) for use with pending ++ // notification IRPs ++ // (f) Unlock byte-range locks (if any were acquired by process) ++ ++ // (g) Attempting to update time stamp values ++ // Errors are ignored... ++ // Not considered as critical errors... ++ ++ /* ++ if( PtrFCB->OpenHandleCount == 1 ) ++ { ++ ULONG CreationTime, AccessTime, ModificationTime; ++ EXT2_INODE Inode; ++ ++ CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart ++ - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); ++ AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart ++ - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); ++ ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart ++ - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); ++ if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ // Update time stamps in the inode... ++ Inode.i_ctime = CreationTime; ++ Inode.i_atime = AccessTime; ++ Inode.i_mtime = ModificationTime; ++ ++ // Updating the inode... ++ Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ); ++ } ++ } ++ */ ++ ++ // (h) Inform the Cache Manager to uninitialize Cache Maps ... ++ CcUninitializeCacheMap( PtrFileObject, NULL, NULL ); ++ ++ // (i) Decrementing the Open Handle count... ++ if( PtrFCB->OpenHandleCount ) ++ { ++ InterlockedDecrement( &PtrFCB->OpenHandleCount ); ++ } ++ else ++ { ++ Ext2BreakPoint(); ++ } ++ ++ PtrFCB->FCBFlags |= FO_CLEANUP_COMPLETE; ++ ++ DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Cleanup]", PtrFCB->ReferenceCount ); ++ DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Cleanup]", PtrFCB->OpenHandleCount ); ++ ++ // (j) Remove share access... ++ // Will do that later ;) ++ ++ // (k) Is this a close on delete file? ++ // If so, delete the file... ++ if( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE) && ++ !PtrFCB->OpenHandleCount ) ++ { ++ // ++ // Have to delete this file... ++ // ++ Ext2DeleteFile( PtrFCB, PtrIrpContext ); ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = 0; ++ PtrFCB->INodeNo = 0; ++ } ++ } ++ else ++ { ++ // This must be a volume close... ++ // Just go ahead and complete this IRP... ++ PtrVCB->VCBOpenCount--; ++ DebugTrace(DEBUG_TRACE_MISC, "VCB Cleanup Requested !!!", 0); ++ CompleteIrp = TRUE; ++ } ++ ++ try_return( RC ); ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ if(PtrResourceAcquired) ++ { ++ Ext2ReleaseResource(PtrResourceAcquired); ++ DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** Resource Released [Cleanup]", 0); ++ DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", ++ PtrResourceAcquired->ActiveCount, ++ PtrResourceAcquired->NumberOfExclusiveWaiters, ++ PtrResourceAcquired->NumberOfSharedWaiters ); ++ ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); ++ } ++ ++ } ++ ++ if( AcquiredVCB ) ++ { ++ ASSERT(PtrVCB); ++ Ext2ReleaseResource(&(PtrVCB->VCBResource)); ++ DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** VCB Released [Cleanup]", 0); ++ DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); ++ AcquiredVCB = FALSE; ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject); ++ } ++ ++ } ++ ++ if( PostRequest ) ++ { ++ RC = Ext2PostRequest(PtrIrpContext, PtrIrp); ++ } ++ if( RC != STATUS_PENDING ) ++ { ++ Ext2ReleaseIrpContext( PtrIrpContext ); ++ // complete the IRP ++ IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT ); ++ } ++ } // end of "finally" processing ++ ++ return(RC); ++} diff --cc reactos/drivers/filesystems/ext2/src/close.c index 00000000000,00000000000..8b83497b64d new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/close.c @@@ -1,0 -1,0 +1,459 @@@ ++/************************************************************************* ++* ++* File: close.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Should contain code to handle the "Close" dispatch entry point. ++* This file serves as a placeholder. Please update this file as part ++* of designing and implementing your FSD. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_CLOSE ++ ++#define DEBUG_LEVEL (DEBUG_TRACE_CLOSE) ++ ++ ++/************************************************************************* ++* ++* Function: Ext2Close() ++* ++* Description: ++* The I/O Manager will invoke this routine to handle a close ++* request ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution ++* to be deferred to a worker thread context) ++* ++* Return Value: Does not matter! ++* ++*************************************************************************/ ++NTSTATUS Ext2Close( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp) // I/O Request Packet ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ BOOLEAN AreWeTopLevel = FALSE; ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Close IRP Received...", 0); ++ ++ ++ FsRtlEnterFileSystem(); ++ ++ ASSERT(DeviceObject); ++ ASSERT(Irp); ++ ++ // set the top level context ++ AreWeTopLevel = Ext2IsIrpTopLevel(Irp); ++ ++ try ++ { ++ ++ // get an IRP context structure and issue the request ++ PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); ++ ASSERT(PtrIrpContext); ++ ++ RC = Ext2CommonClose(PtrIrpContext, Irp, TRUE); ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, Irp); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ if (AreWeTopLevel) ++ { ++ IoSetTopLevelIrp(NULL); ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2CommonClose() ++* ++* Description: ++* The actual work is performed here. This routine may be invoked in one' ++* of the two possible contexts: ++* (a) in the context of a system worker thread ++* (b) in the context of the original caller ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: Does not matter! ++* ++*************************************************************************/ ++NTSTATUS Ext2CommonClose( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++BOOLEAN FirstAttempt ) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PIO_STACK_LOCATION PtrIoStackLocation = NULL; ++ PFILE_OBJECT PtrFileObject = NULL; ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2VCB PtrVCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ PERESOURCE PtrResourceAcquired = NULL; ++ IO_STATUS_BLOCK LocalIoStatus; ++ ++ BOOLEAN CompleteIrp = TRUE; ++ BOOLEAN PostRequest = FALSE; ++ BOOLEAN AcquiredVCB = FALSE; ++ BOOLEAN CanWait = FALSE; ++ BOOLEAN BlockForResource; ++ int i = 1; ++ ++ try ++ { ++ // First, get a pointer to the current I/O stack location ++ PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ++ ASSERT(PtrIoStackLocation); ++ ++ PtrFileObject = PtrIoStackLocation->FileObject; ++ ASSERT(PtrFileObject); ++ ++ if( !PtrFileObject->FsContext2 ) ++ { ++ // This must be a Cleanup request received ++ // as a result of IoCreateStreamFileObject ++ // Only such a File object would have a NULL CCB ++ ++ DebugTrace( DEBUG_TRACE_SPECIAL, " === Close with NULL CCB", 0); ++ if( PtrFileObject ) ++ { ++ DebugTrace( DEBUG_TRACE_SPECIAL, "###### File Pointer 0x%LX [Close]", PtrFileObject); ++ } ++ Ext2BreakPoint(); ++ try_return( RC ); ++ } ++ ++ // Get the FCB and CCB pointers ++ ++ Ext2GetFCB_CCB_VCB_FromFileObject ( ++ PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); ++ ++ PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); ++ ASSERT( PtrVCB ); ++ ++ if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) ++ //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -null-", 0); ++ } ++ ++ // (a) Acquiring the VCBResource Exclusively... ++ // This is done to synchronise with the close and cleanup routines... ++// if( ExTryToAcquireResourceExclusiveLite(&(PtrVCB->VCBResource) ) ) ++ ++ BlockForResource = !FirstAttempt; ++ if( !FirstAttempt ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Close]", 0); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [Close]", 0); ++ } ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); ++ } ++ i = 1; ++ while( !AcquiredVCB ) ++ { ++ DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); ++ if(! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [Close]", 0); ++ if( BlockForResource && i != 1000 ) ++ { ++ LARGE_INTEGER Delay; ++ ++ //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); ++ ++ Delay.QuadPart = -500 * i; ++ KeDelayExecutionThread( KernelMode, FALSE, &Delay ); ++ DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); ++ } ++ else ++ { ++ if( i == 1000 ) ++ DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); ++ PostRequest = TRUE; ++ try_return( RC = STATUS_PENDING ); ++ } ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in [Close]", 0); ++ AcquiredVCB = TRUE; ++ } ++ i *= 10; ++ } ++ ++ // (b) Acquire the file (FCB) exclusively ++ if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) ++ { ++ // This FCB is an FCB indeed. ;) ++ // So acquiring it exclusively... ++ // This is done to synchronise with read/write routines... ++ if( !FirstAttempt ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively [Close]", 0); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [Close]", 0); ++ } ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); ++ } ++ i = 1; ++ while( !PtrResourceAcquired ) ++ { ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ ++ DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ++ if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Close]", 0); ++ if( BlockForResource && i != 1000 ) ++ { ++ LARGE_INTEGER Delay; ++ ++ //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); ++ ++ Delay.QuadPart = -500 * i; ++ KeDelayExecutionThread( KernelMode, FALSE, &Delay ); ++ DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); ++ } ++ else ++ { ++ if( i == 1000 ) ++ DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); ++ PostRequest = TRUE; ++ try_return( RC = STATUS_PENDING ); ++ } ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [Close]", 0); ++ PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource ); ++ } ++ i *= 10; ++ } ++ ++ // (c) Delete the CCB structure (free memory) ++ RemoveEntryList( &PtrCCB->NextCCB ); ++ Ext2ReleaseCCB( PtrCCB ); ++ PtrFileObject->FsContext2 = NULL; ++ ++ // (d) Decrementing the Reference Count... ++ if( PtrFCB->ReferenceCount ) ++ { ++ InterlockedDecrement( &PtrFCB->ReferenceCount ); ++ } ++ else ++ { ++ Ext2BreakPoint(); ++ } ++ DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Close]", PtrFCB->ReferenceCount ); ++ DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Close]", PtrFCB->OpenHandleCount ); ++ if( PtrFCB->ReferenceCount == 0 ) ++ { ++ ++ // Attempting to update time stamp values ++ // Errors are ignored... ++ // Not considered as critical errors... ++ ++ { ++ ULONG CreationTime, AccessTime, ModificationTime; ++ EXT2_INODE Inode; ++ ++ CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart ++ - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); ++ AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart ++ - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); ++ ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart ++ - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); ++ if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ // Update time stamps in the inode... ++ Inode.i_ctime = CreationTime; ++ Inode.i_atime = AccessTime; ++ Inode.i_mtime = ModificationTime; ++ ++ // Updating the inode... ++ Ext2WriteInode( NULL, PtrVCB, PtrFCB->INodeNo, &Inode ); ++ } ++ } ++ ++ ++ if( PtrFCB->INodeNo == EXT2_ROOT_INO ) ++ { ++ // ++ // Root Directory FCB ++ // Preserve this ++ // FSD has a File Object for this FCB... ++ // ++ DebugTrace(DEBUG_TRACE_MISC, "^^^^^Root Directory FCB ; leaveing it alone[Close]", 0); ++ // Do nothing... ++ ++ } ++ else if( PtrFCB->DcbFcb.Dcb.PtrDirFileObject ) ++ { ++ // ++ // If this is a FCB created on the FSD's initiative ++ // Leave it alone ++ // ++ DebugTrace(DEBUG_TRACE_MISC, "^^^^^FCB Created on the FSD's initiative; leaveing it alone[Close]", 0); ++ if( !PtrFCB->ClosableFCBs.OnClosableFCBList ) ++ { ++ InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, ++ &PtrFCB->ClosableFCBs.ClosableFCBList ); ++ PtrVCB->ClosableFCBs.Count++; ++ ++ PtrFCB->ClosableFCBs.OnClosableFCBList = TRUE; ++ } ++ ++ if( PtrVCB->ClosableFCBs.Count > EXT2_MAXCLOSABLE_FCBS_UL ) ++ { ++ PtrExt2FCB PtrTempFCB = NULL; ++ // Checking if Closable FCBs are too many in number... ++ // Shouldn't block the ++ // Should do this asynchronously... ++ // Maybe later... ++ PLIST_ENTRY PtrEntry = NULL; ++ ++ PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead ); ++ ++ PtrTempFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList ); ++ if( Ext2CloseClosableFCB( PtrTempFCB ) ) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Close]", PtrTempFCB ); ++ ExFreePool( PtrTempFCB ); ++ PtrVCB->ClosableFCBs.Count--; ++ } ++ else ++ { ++ // Put the FCB back in the list... ++ InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, ++ &PtrTempFCB->ClosableFCBs.ClosableFCBList ); ++ } ++ DebugTrace( DEBUG_TRACE_SPECIAL, "ClosableFCBs Count = %ld [Close]", PtrVCB->ClosableFCBs.Count ); ++ } ++ } ++ else ++ { ++ // Remove this FCB as well... ++ DebugTrace(DEBUG_TRACE_MISC, "^^^^^Deleting FCB [Close]", 0); ++ RemoveEntryList( &PtrFCB->NextFCB ); ++ ++ if ( PtrResourceAcquired ) ++ { ++ Ext2ReleaseResource(PtrResourceAcquired); ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); ++ DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Close]", ++ PtrResourceAcquired->ActiveCount, ++ PtrResourceAcquired->NumberOfExclusiveWaiters, ++ PtrResourceAcquired->NumberOfSharedWaiters ); ++ ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); ++ } ++ PtrResourceAcquired = FALSE; ++ } ++ Ext2ReleaseFCB( PtrFCB ); ++ } ++ ++ } ++ CompleteIrp = TRUE; ++ } ++ else ++ { ++ // This must be a volume close... ++ // What do I do now? ;) ++ DebugTrace(DEBUG_TRACE_MISC, "VCB Close Requested !!!", 0); ++ CompleteIrp = TRUE; ++ } ++ try_return( RC ); ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ if ( PtrResourceAcquired ) ++ { ++ Ext2ReleaseResource(PtrResourceAcquired); ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); ++ DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Close]", ++ PtrResourceAcquired->ActiveCount, ++ PtrResourceAcquired->NumberOfExclusiveWaiters, ++ PtrResourceAcquired->NumberOfSharedWaiters ); ++ ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); ++ } ++ PtrResourceAcquired = FALSE; ++ } ++ ++ if (AcquiredVCB) ++ { ++ ASSERT(PtrVCB); ++ Ext2ReleaseResource(&(PtrVCB->VCBResource)); ++ DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); ++ DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Close]", 0); ++ ++ AcquiredVCB = FALSE; ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); ++ } ++ ++ } ++ ++ if( PostRequest ) ++ { ++ RC = Ext2PostRequest(PtrIrpContext, PtrIrp); ++ } ++ else if( CompleteIrp && RC != STATUS_PENDING ) ++ { ++ // complete the IRP ++ IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT ); ++ ++ Ext2ReleaseIrpContext( PtrIrpContext ); ++ } ++ ++ } // end of "finally" processing ++ ++ return(RC); ++} diff --cc reactos/drivers/filesystems/ext2/src/create.c index 00000000000,00000000000..13fe4e13b49 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/create.c @@@ -1,0 -1,0 +1,1681 @@@ ++/************************************************************************* ++* ++* File: create.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains code to handle the "Create"/"Open" dispatch entry point. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_CREATE ++ ++#define DEBUG_LEVEL (DEBUG_TRACE_CREATE) ++ ++ ++/************************************************************************* ++* ++* Function: Ext2Create() ++* ++* Description: ++* The I/O Manager will invoke this routine to handle a create/open ++* request ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution ++* to be deferred to a worker thread context) ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2Create( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp) // I/O Request Packet ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext; ++ BOOLEAN AreWeTopLevel = FALSE; ++ ++ DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Create Control IRP received...", 0); ++ ++ FsRtlEnterFileSystem(); ++ ++ // Ext2BreakPoint(); ++ ++ ASSERT(DeviceObject); ++ ASSERT(Irp); ++ ++ // sometimes, we may be called here with the device object representing ++ // the file system (instead of the device object created for a logical ++ // volume. In this case, there is not much we wish to do (this create ++ // typically will happen 'cause some process has to open the FSD device ++ // object so as to be able to send an IOCTL to the FSD) ++ ++ // All of the logical volume device objects we create have a device ++ // extension whereas the device object representing the FSD has no ++ // device extension. This seems like a good enough method to identify ++ // between the two device objects ... ++ if (DeviceObject->Size == (unsigned short)(sizeof(DEVICE_OBJECT))) ++ { ++ // this is an open of the FSD itself ++ DebugTrace( DEBUG_TRACE_MISC, " === Open for the FSD itself", 0); ++ Irp->IoStatus.Status = RC; ++ Irp->IoStatus.Information = FILE_OPENED; ++ ++ IoCompleteRequest(Irp, IO_NO_INCREMENT); ++ return(RC); ++ } ++ ++ // set the top level context ++ AreWeTopLevel = Ext2IsIrpTopLevel(Irp); ++ ++ try ++ { ++ ++ // get an IRP context structure and issue the request ++ PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); ++ ASSERT(PtrIrpContext); ++ ++ RC = Ext2CommonCreate(PtrIrpContext, Irp, TRUE ); ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, Irp); ++ ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ if (AreWeTopLevel) ++ { ++ IoSetTopLevelIrp(NULL); ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++ ++ ++/************************************************************************* ++* ++* Function: Ext2CommonCreate() ++* ++* Description: ++* The actual work is performed here. This routine may be invoked in one' ++* of the two possible contexts: ++* (a) in the context of a system worker thread ++* (b) in the context of the original caller ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2CommonCreate( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp, ++BOOLEAN FirstAttempt) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PIO_STACK_LOCATION PtrIoStackLocation = NULL; ++ PIO_SECURITY_CONTEXT PtrSecurityContext = NULL; ++ PFILE_OBJECT PtrNewFileObject = NULL; ++ PFILE_OBJECT PtrRelatedFileObject = NULL; ++ uint32 AllocationSize = 0; // if we create a new file ++ PFILE_FULL_EA_INFORMATION PtrExtAttrBuffer = NULL; ++ unsigned long RequestedOptions = 0; ++ unsigned long RequestedDisposition = 0; ++ uint8 FileAttributes = 0; ++ unsigned short ShareAccess = 0; ++ unsigned long ExtAttrLength = 0; ++ ACCESS_MASK DesiredAccess; ++ ++ BOOLEAN DeferredProcessing = FALSE; ++ ++ PtrExt2VCB PtrVCB = NULL; ++ BOOLEAN AcquiredVCB = FALSE; ++ ++ BOOLEAN DirectoryOnlyRequested = FALSE; ++ BOOLEAN FileOnlyRequested = FALSE; ++ BOOLEAN NoBufferingSpecified = FALSE; ++ BOOLEAN WriteThroughRequested = FALSE; ++ BOOLEAN DeleteOnCloseSpecified = FALSE; ++ BOOLEAN NoExtAttrKnowledge = FALSE; ++ BOOLEAN CreateTreeConnection = FALSE; ++ BOOLEAN OpenByFileId = FALSE; ++ ++ BOOLEAN SequentialOnly = FALSE; ++ BOOLEAN RandomAccess = FALSE; ++ ++ // Are we dealing with a page file? ++ BOOLEAN PageFileManipulation = FALSE; ++ ++ // Is this open for a target directory (used in rename operations)? ++ BOOLEAN OpenTargetDirectory = FALSE; ++ ++ // Should we ignore case when attempting to locate the object? ++ BOOLEAN IgnoreCaseWhenChecking = FALSE; ++ ++ PtrExt2CCB PtrRelatedCCB = NULL, PtrNewCCB = NULL; ++ PtrExt2FCB PtrRelatedFCB = NULL, PtrNewFCB = NULL; ++ ++ unsigned long ReturnedInformation = -1; ++ ++ UNICODE_STRING TargetObjectName; ++ UNICODE_STRING RelatedObjectName; ++ ++ UNICODE_STRING AbsolutePathName; ++ UNICODE_STRING RenameLinkTargetFileName; ++ ++ LARGE_INTEGER FileAllocationSize, FileEndOfFile; ++ ++ ++ ASSERT(PtrIrpContext); ++ ASSERT(PtrIrp); ++ ++ try ++ { ++ ++ AbsolutePathName.Buffer = NULL; ++ AbsolutePathName.Length = AbsolutePathName.MaximumLength = 0; ++ ++ // Getting a pointer to the current I/O stack location ++ PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ++ ASSERT(PtrIoStackLocation); ++ ++ // Can we block? ++ if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK)) ++ { ++ // Asynchronous processing required... ++ RC = Ext2PostRequest(PtrIrpContext, PtrIrp); ++ DeferredProcessing = TRUE; ++ try_return(RC); ++ } ++ ++ // Obtaining the parameters specified by the user. ++ PtrNewFileObject = PtrIoStackLocation->FileObject; ++ TargetObjectName = PtrNewFileObject->FileName; ++ PtrRelatedFileObject = PtrNewFileObject->RelatedFileObject; ++ ++ if( PtrNewFileObject->FileName.Length && PtrNewFileObject->FileName.Buffer ) ++ { ++ if( PtrNewFileObject->FileName.Buffer[ PtrNewFileObject->FileName.Length/2 ] != 0 ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrFileObject->FileName not NULL terminated! [Create]", 0 ); ++ } ++ DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -%S- [Create]", PtrNewFileObject->FileName.Buffer ); ++ } ++ else ++ { ++ DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -null- [Create]", 0); ++ } ++ ++ // Is this a Relative Create/Open? ++ if (PtrRelatedFileObject) ++ { ++ PtrRelatedCCB = (PtrExt2CCB)(PtrRelatedFileObject->FsContext2); ++ ASSERT(PtrRelatedCCB); ++ ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); ++ // each CCB in turn points to a FCB ++ PtrRelatedFCB = PtrRelatedCCB->PtrFCB; ++ ASSERT(PtrRelatedFCB); ++ if( PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB && ++ PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB ) ++ { ++ // How the hell can this happen!!! ++ Ext2BreakPoint(); ++ } ++ ++ AssertFCBorVCB( PtrRelatedFCB ); ++ ++ RelatedObjectName = PtrRelatedFileObject->FileName; ++ ++ if( PtrRelatedFileObject->FileName.Length && PtrRelatedFileObject->FileName.Buffer ) ++ { ++ DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -%S-", PtrRelatedFileObject->FileName.Buffer ); ++ } ++ else ++ { ++ DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -null-",0); ++ } ++ ++ } ++ ++ ++ AllocationSize = PtrIrp->Overlay.AllocationSize.LowPart; ++ // Only 32 bit file sizes supported... ++ ++ if (PtrIrp->Overlay.AllocationSize.HighPart) ++ { ++ RC = STATUS_INVALID_PARAMETER; ++ try_return(RC); ++ } ++ ++ // Getting a pointer to the supplied security context ++ PtrSecurityContext = PtrIoStackLocation->Parameters.Create.SecurityContext; ++ ++ // Obtaining the desired access ++ DesiredAccess = PtrSecurityContext->DesiredAccess; ++ ++ // Getting the options supplied by the user... ++ RequestedOptions = (PtrIoStackLocation->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS); ++ RequestedDisposition = ((PtrIoStackLocation->Parameters.Create.Options >> 24) & 0xFF); ++ ++ FileAttributes = (uint8)(PtrIoStackLocation->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS); ++ ShareAccess = PtrIoStackLocation->Parameters.Create.ShareAccess; ++ PtrExtAttrBuffer = PtrIrp->AssociatedIrp.SystemBuffer; ++ ++ ExtAttrLength = PtrIoStackLocation->Parameters.Create.EaLength; ++ ++ SequentialOnly = ((RequestedOptions & FILE_SEQUENTIAL_ONLY ) ? TRUE : FALSE); ++ RandomAccess = ((RequestedOptions & FILE_RANDOM_ACCESS ) ? TRUE : FALSE); ++ ++ ++ DirectoryOnlyRequested = ((RequestedOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE); ++ FileOnlyRequested = ((RequestedOptions & FILE_NON_DIRECTORY_FILE) ? TRUE : FALSE); ++ NoBufferingSpecified = ((RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING) ? TRUE : FALSE); ++ WriteThroughRequested = ((RequestedOptions & FILE_WRITE_THROUGH) ? TRUE : FALSE); ++ DeleteOnCloseSpecified = ((RequestedOptions & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE); ++ NoExtAttrKnowledge = ((RequestedOptions & FILE_NO_EA_KNOWLEDGE) ? TRUE : FALSE); ++ CreateTreeConnection = ((RequestedOptions & FILE_CREATE_TREE_CONNECTION) ? TRUE : FALSE); ++ OpenByFileId = ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? TRUE : FALSE); ++ PageFileManipulation = ((PtrIoStackLocation->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE); ++ OpenTargetDirectory = ((PtrIoStackLocation->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE); ++ IgnoreCaseWhenChecking = ((PtrIoStackLocation->Flags & SL_CASE_SENSITIVE) ? TRUE : FALSE); ++ ++ // Ensure that the operation has been directed to a valid VCB ... ++ PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); ++ ASSERT(PtrVCB); ++ ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); ++ ++ ++ if( !PtrNewFileObject->Vpb ) ++ { ++ PtrNewFileObject->Vpb = PtrVCB->PtrVPB; ++ } ++ ++ // Acquiring the VCBResource Exclusively... ++ // This is done to synchronise with the close and cleanup routines... ++ ++ DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Create]", 0); ++ ++ DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Create]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); ++ ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE); ++ ++ AcquiredVCB = TRUE; ++ ++ DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in Create", 0); ++ if( PtrNewFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Create]", PtrNewFileObject); ++ } ++ ++ // Verify Volume... ++ // if (!NT_SUCCESS(RC = Ext2VerifyVolume(PtrVCB))) ++ // { ++ // try_return(RC); ++ // } ++ ++ // If the volume has been locked, fail the request ++ ++ if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_LOCKED) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "Volume locked. Failing Create", 0 ); ++ RC = STATUS_ACCESS_DENIED; ++ try_return(RC); ++ } ++ ++ ++ if ((PtrNewFileObject->FileName.Length == 0) && ((PtrRelatedFileObject == NULL) || ++ (PtrRelatedFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB))) ++ { ++ // ++ // >>>>>>>>>>>>> Volume Open requested. <<<<<<<<<<<<< ++ // ++ ++ // Performing validity checks... ++ if ((OpenTargetDirectory) || (PtrExtAttrBuffer)) ++ { ++ RC = STATUS_INVALID_PARAMETER; ++ try_return(RC); ++ } ++ ++ if (DirectoryOnlyRequested) ++ { ++ // a volume is not a directory ++ RC = STATUS_NOT_A_DIRECTORY; ++ try_return(RC); ++ } ++ ++ if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) ++ { ++ // cannot create a new volume, I'm afraid ... ++ RC = STATUS_ACCESS_DENIED; ++ try_return(RC); ++ } ++ DebugTrace(DEBUG_TRACE_MISC, "Volume open requested", 0 ); ++ RC = Ext2OpenVolume(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject); ++ ReturnedInformation = PtrIrp->IoStatus.Information; ++ ++ try_return(RC); ++ } ++ ++ if (OpenByFileId) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "Open by File Id requested", 0 ); ++ RC = STATUS_ACCESS_DENIED; ++ try_return(RC); ++ } ++ ++ // Relative path name specified... ++ if (PtrRelatedFileObject) ++ { ++ ++ if (!(PtrRelatedFCB->FCBFlags & EXT2_FCB_DIRECTORY)) ++ { ++ // we must have a directory as the "related" object ++ RC = STATUS_INVALID_PARAMETER; ++ try_return(RC); ++ } ++ ++ // Performing validity checks... ++ if ((RelatedObjectName.Length == 0) || (RelatedObjectName.Buffer[0] != L'\\')) ++ { ++ RC = STATUS_INVALID_PARAMETER; ++ try_return(RC); ++ } ++ ++ if ((TargetObjectName.Length != 0) && (TargetObjectName.Buffer[0] == L'\\')) ++ { ++ RC = STATUS_INVALID_PARAMETER; ++ try_return(RC); ++ } ++ ++ // Creating an absolute path-name. ++ { ++ AbsolutePathName.MaximumLength = TargetObjectName.Length + RelatedObjectName.Length + sizeof(WCHAR); ++ if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) ++ { ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return(RC); ++ } ++ ++ RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength); ++ ++ RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(RelatedObjectName.Buffer), RelatedObjectName.Length); ++ AbsolutePathName.Length = RelatedObjectName.Length; ++ RtlAppendUnicodeToString(&AbsolutePathName, L"\\"); ++ RtlAppendUnicodeToString(&AbsolutePathName, TargetObjectName.Buffer); ++ } ++ ++ } ++ // Absolute Path name specified... ++ else ++ { ++ ++ ++ // Validity Checks... ++ if (TargetObjectName.Buffer[0] != L'\\') ++ { ++ RC = STATUS_INVALID_PARAMETER; ++ try_return(RC); ++ } ++ ++ { ++ AbsolutePathName.MaximumLength = TargetObjectName.Length; ++ if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) { ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return(RC); ++ } ++ ++ RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength); ++ ++ RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(TargetObjectName.Buffer), TargetObjectName.Length); ++ AbsolutePathName.Length = TargetObjectName.Length; ++ } ++ } ++ ++ ++ // Parsing the path... ++ if (AbsolutePathName.Length == 2) ++ { ++ ++ // this is an open of the root directory, ensure that the caller has not requested a file only ++ if (FileOnlyRequested || (RequestedDisposition == FILE_SUPERSEDE) || (RequestedDisposition == FILE_OVERWRITE) || ++ (RequestedDisposition == FILE_OVERWRITE_IF)) ++ { ++ RC = STATUS_FILE_IS_A_DIRECTORY; ++ try_return(RC); ++ } ++ ++ RC = Ext2OpenRootDirectory(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject); ++ DebugTrace(DEBUG_TRACE_MISC, " === Root directory opened", 0 ); ++ try_return(RC); ++ } ++ ++ ++ { ++ // Used during parsing the file path... ++ UNICODE_STRING RemainingName; ++ UNICODE_STRING CurrentName; ++ UNICODE_STRING NextRemainingName; ++ PEXT2_INODE PtrNextInode = NULL; ++ ULONG CurrInodeNo = 0; ++ PtrExt2FCB PtrCurrFCB = NULL; ++ PtrExt2FCB PtrNextFCB = NULL; ++ PFILE_OBJECT PtrCurrFileObject = NULL; ++ UINT NameBufferIndex; ++ ULONG Type = 0; ++ LARGE_INTEGER ZeroSize; ++ BOOLEAN Found = FALSE; ++ ++ ZeroSize.QuadPart = 0; ++ if ( PtrRelatedFileObject ) ++ { ++ CurrInodeNo = PtrRelatedFCB->INodeNo; ++ PtrCurrFCB = PtrRelatedFCB; ++ } ++ else ++ { ++ CurrInodeNo = PtrVCB->PtrRootDirectoryFCB->INodeNo; ++ PtrCurrFCB = PtrVCB->PtrRootDirectoryFCB; ++ ++ } ++ ++ // Ext2ZerooutUnicodeString( &RemainingName ); ++ Ext2ZerooutUnicodeString( &CurrentName ); ++ Ext2ZerooutUnicodeString( &NextRemainingName ); ++ ++ RemainingName = TargetObjectName; ++ ++ while ( !Found && CurrInodeNo ) ++ { ++ FsRtlDissectName ( RemainingName, &CurrentName, &NextRemainingName ); ++ ++ RemainingName = NextRemainingName; ++ // CurrInodeNo is the parent inode for the entry I am searching for ++ // PtrCurrFCB is the parent's FCB ++ // Current Name is its name... ++ ++ ++ PtrNextFCB = Ext2LocateChildFCBInCore ( PtrVCB, &CurrentName, CurrInodeNo ); ++ ++ if( PtrNextFCB ) ++ { ++ CurrInodeNo = PtrNextFCB->INodeNo; ++ ++ if( NextRemainingName.Length == 0 ) ++ { ++ // ++ // Done Parsing... ++ // Found the file... ++ // ++ Found = TRUE; ++ ++ if( OpenTargetDirectory ) ++ { ++ int i; ++ // ++ // This is for a rename/move operation... ++ // ++ ReturnedInformation = FILE_EXISTS; ++ ++ // Now replace the file name field with that of the ++ // Target file name... ++ Ext2CopyUnicodeString( ++ &RenameLinkTargetFileName, ++ &CurrentName ); ++ /* ++ ++ for( i = 0; i < (CurrentName.Length/2); i++ ) ++ { ++ PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i]; ++ } ++ PtrNewFileObject->FileName.Length = CurrentName.Length; ++ */ ++ // Now open the Parent Directory... ++ PtrNextFCB = PtrCurrFCB; ++ CurrInodeNo = PtrNextFCB->INodeNo; ++ } ++ ++ // ++ // Relating the FCB to the New File Object ++ // ++ PtrNewFileObject->Vpb = PtrVCB->PtrVPB; ++ PtrNewFileObject->PrivateCacheMap = NULL; ++ PtrNewFileObject->FsContext = (void *)( &(PtrNextFCB->NTRequiredFCB.CommonFCBHeader) ); ++ PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject) ; ++ break; ++ } ++ ++ else if( !Ext2IsFlagOn( PtrNextFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) ++ { ++ // Invalid path... ++ // Can have only a directory in the middle of the path... ++ // ++ RC = STATUS_OBJECT_PATH_NOT_FOUND; ++ try_return( RC ); ++ } ++ } ++ else // searching on the disk... ++ { ++ CurrInodeNo = Ext2LocateFileInDisk( PtrVCB, &CurrentName, PtrCurrFCB, &Type ); ++ if( !CurrInodeNo ) ++ { ++ // ++ // Not found... ++ // Quit searching... ++ // ++ ++ if( ( NextRemainingName.Length == 0 ) && ++ ( RequestedDisposition == FILE_CREATE ) || ++ ( RequestedDisposition == FILE_OPEN_IF) || ++ ( RequestedDisposition == FILE_OVERWRITE_IF) ) ++ ++ { ++ // ++ // Just the last component was not found... ++ // A create was requested... ++ // ++ if( DirectoryOnlyRequested ) ++ { ++ Type = EXT2_FT_DIR; ++ } ++ else ++ { ++ Type = EXT2_FT_REG_FILE; ++ } ++ ++ CurrInodeNo = Ext2CreateFile( PtrIrpContext, PtrVCB, ++ &CurrentName, PtrCurrFCB, Type ); ++ ++ if( !CurrInodeNo ) ++ { ++ RC = STATUS_OBJECT_PATH_NOT_FOUND; ++ try_return( RC ); ++ } ++ // Set the allocation size for the object is specified ++ //IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess)); ++ // RC = STATUS_SUCCESS; ++ ReturnedInformation = FILE_CREATED; ++ ++ // Should also create a CCB structure... ++ // Doing that a little fathre down... ;) ++ ++ } ++ else if( NextRemainingName.Length == 0 && OpenTargetDirectory ) ++ { ++ int i; ++ // ++ // This is for a rename/move operation... ++ // Just the last component was not found... ++ // ++ ReturnedInformation = FILE_DOES_NOT_EXIST; ++ ++ // Now replace the file name field with that of the ++ // Target file name... ++ Ext2CopyUnicodeString( ++ &RenameLinkTargetFileName, ++ &CurrentName ); ++ /* ++ for( i = 0; i < (CurrentName.Length/2); i++ ) ++ { ++ PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i]; ++ } ++ PtrNewFileObject->FileName.Length = CurrentName.Length; ++ */ ++ ++ // Now open the Parent Directory... ++ PtrNextFCB = PtrCurrFCB; ++ CurrInodeNo = PtrNextFCB->INodeNo; ++ // Initialize the FsContext ++ PtrNewFileObject->FsContext = &PtrNextFCB->NTRequiredFCB.CommonFCBHeader; ++ // Initialize the section object pointer... ++ PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject); ++ PtrNewFileObject->Vpb = PtrVCB->PtrVPB; ++ PtrNewFileObject->PrivateCacheMap = NULL; ++ ++ break; ++ } ++ else ++ { ++ RC = STATUS_OBJECT_PATH_NOT_FOUND; ++ try_return( RC ); ++ } ++ } ++ ++ if( NextRemainingName.Length ) ++ { ++ // Should be a directory... ++ if( Type != EXT2_FT_DIR ) ++ { ++ // Invalid path... ++ // Can have only a directory in the middle of the path... ++ // ++ RC = STATUS_OBJECT_PATH_NOT_FOUND; ++ try_return( RC ); ++ } ++ ++ PtrCurrFileObject = NULL; ++ } ++ else ++ { ++ // ++ // Done Parsing... ++ // Found the file... ++ // ++ Found = TRUE; ++ ++ // ++ // Was I supposed to create a new file? ++ // ++ if (RequestedDisposition == FILE_CREATE && ++ ReturnedInformation != FILE_CREATED ) ++ { ++ ReturnedInformation = FILE_EXISTS; ++ RC = STATUS_OBJECT_NAME_COLLISION; ++ try_return(RC); ++ } ++ ++ // Is this the type of file I was looking for? ++ // Do some checking here... ++ ++ if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE ) ++ { ++ // Deny access! ++ // Cannot open a special file... ++ RC = STATUS_ACCESS_DENIED; ++ try_return( RC ); ++ ++ } ++ if( DirectoryOnlyRequested && Type != EXT2_FT_DIR ) ++ { ++ RC = STATUS_NOT_A_DIRECTORY; ++ try_return( RC ); ++ } ++ if( FileOnlyRequested && Type == EXT2_FT_DIR ) ++ { ++ RC = STATUS_FILE_IS_A_DIRECTORY; ++ try_return(RC); ++ } ++ ++ PtrCurrFileObject = PtrNewFileObject; ++ // Things seem to be ok enough! ++ // Proceeing with the Open/Create... ++ ++ } ++ ++ ++ // ++ // Create an FCB and initialise it... ++ // ++ { ++ PtrExt2ObjectName PtrObjectName; ++ ++ // Initialising the object name... ++ PtrObjectName = Ext2AllocateObjectName(); ++ Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &CurrentName ); ++ // RtlInitUnicodeString( &PtrObjectName->ObjectName, CurrentName.Buffer ); ++ ++ if( !NT_SUCCESS( Ext2CreateNewFCB( ++ &PtrNextFCB, // the new FCB ++ ZeroSize, // AllocationSize, ++ ZeroSize, // EndOfFile, ++ PtrCurrFileObject, // The File Object ++ PtrVCB, ++ PtrObjectName ) ) ) ++ { ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return(RC); ++ } ++ ++ if( Type == EXT2_FT_DIR ) ++ PtrNextFCB->FCBFlags |= EXT2_FCB_DIRECTORY; ++ else if( Type != EXT2_FT_REG_FILE ) ++ PtrNextFCB->FCBFlags |= EXT2_FCB_SPECIAL_FILE; ++ ++ PtrNextFCB->INodeNo = CurrInodeNo ; ++ PtrNextFCB->ParentINodeNo = PtrCurrFCB->INodeNo; ++ ++ if( PtrCurrFileObject == NULL && CurrInodeNo != EXT2_ROOT_INO ) ++ { ++ // This is an FCB created to cache the reads done while parsing ++ // Put this FCB on the ClosableFCBList ++ if( !PtrNextFCB->ClosableFCBs.OnClosableFCBList ) ++ { ++ InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, ++ &PtrNextFCB->ClosableFCBs.ClosableFCBList ); ++ PtrVCB->ClosableFCBs.Count++; ++ PtrNextFCB->ClosableFCBs.OnClosableFCBList = TRUE; ++ } ++ } ++ } ++ } ++ ++ // ++ // Still not done parsing... ++ // miles to go before I open... ;) ++ // ++ PtrCurrFCB = PtrNextFCB; ++ } ++ ++ PtrNewFCB = PtrNextFCB; ++ } ++ ++ ++ // If I get this far... ++ // it means, I have located the file... ++ // I even have an FCB to represent it!!! ++ ++ if ( NT_SUCCESS (RC) ) ++ { ++ ++ if ((PtrNewFCB->FCBFlags & EXT2_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) || ++ (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF ))) ++ { ++ RC = STATUS_FILE_IS_A_DIRECTORY; ++ try_return(RC); ++ } ++ ++ ++ // Check share access and fail if the share conflicts with an existing ++ // open. ++ ++ if (PtrNewFCB->OpenHandleCount > 0) ++ { ++ // The FCB is currently in use by some thread. ++ // We must check whether the requested access/share access ++ // conflicts with the existing open operations. ++ ++ if (!NT_SUCCESS(RC = IoCheckShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, ++ &(PtrNewFCB->FCBShareAccess), TRUE))) ++ { ++ // Ext2CloseCCB(PtrNewCCB); ++ try_return(RC); ++ } ++ } ++ else ++ { ++ IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess)); ++ } ++ ++ // ++ // Allocating a new CCB Structure... ++ // ++ Ext2CreateNewCCB( &PtrNewCCB, PtrNewFCB, PtrNewFileObject); ++ PtrNewFileObject->FsContext2 = (void *) PtrNewCCB; ++ Ext2CopyUnicodeString( &(PtrNewCCB->AbsolutePathName), &AbsolutePathName ); ++ ++ if( ReturnedInformation == -1 ) ++ { ++ // ++ // ReturnedInformation has not been set so far... ++ // ++ ReturnedInformation = FILE_OPENED; ++ } ++ ++ // If a supersede or overwrite was requested, do so now ... ++ if (RequestedDisposition == FILE_SUPERSEDE) ++ { ++ // Attempt the operation here ... ++ if( Ext2SupersedeFile( PtrNewFCB, PtrIrpContext) ) ++ { ++ ReturnedInformation = FILE_SUPERSEDED; ++ } ++ } ++ ++ else if ((RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF)) ++ { ++ // Attempt the overwrite operation... ++ if( Ext2OverwriteFile( PtrNewFCB, PtrIrpContext) ) ++ { ++ ReturnedInformation = FILE_OVERWRITTEN; ++ } ++ } ++ if( AllocationSize ) ++ { ++ if( ReturnedInformation == FILE_CREATED || ++ ReturnedInformation == FILE_SUPERSEDED ) ++ { ++ ULONG CurrentSize; ++ ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ for( CurrentSize = 0; CurrentSize < AllocationSize; CurrentSize += LogicalBlockSize ) ++ { ++ Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrNewFCB, PtrNewFileObject, FALSE ); ++ } ++ } ++ } ++ ++ if( ReturnedInformation == FILE_CREATED ) ++ { ++ // Allocate some data blocks if ++ // 1. initial file size has been specified... ++ // 2. if the file is a Directory... ++ // In case of (2) make entries for '.' and '..' ++ // Zero out the Blocks... ++ ++ UNICODE_STRING Name; ++ ++ if( DirectoryOnlyRequested ) ++ { ++ ++ Ext2CopyCharToUnicodeString( &Name, ".", 1 ); ++ Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->INodeNo); ++ ++ Name.Buffer[1] = '.'; ++ Name.Buffer[2] = '\0'; ++ Name.Length += 2; ++ Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->ParentINodeNo ); ++ Ext2DeallocateUnicodeString( &Name ); ++ } ++ } ++ if( OpenTargetDirectory ) ++ { ++ // ++ // Save the taget file name in the CCB... ++ // ++ Ext2CopyUnicodeString( ++ &PtrNewCCB->RenameLinkTargetFileName, ++ &RenameLinkTargetFileName ); ++ Ext2DeallocateUnicodeString( &RenameLinkTargetFileName ); ++ } ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ if (AcquiredVCB) ++ { ++ ASSERT(PtrVCB); ++ Ext2ReleaseResource(&(PtrVCB->VCBResource)); ++ ++ AcquiredVCB = FALSE; ++ DebugTrace(DEBUG_TRACE_MISC, "*** VCB released [Create]", 0); ++ ++ if( PtrNewFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Create]", PtrNewFileObject); ++ } ++ } ++ ++ if (AbsolutePathName.Buffer != NULL) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Create]", AbsolutePathName.Buffer ); ++ ExFreePool(AbsolutePathName.Buffer); ++ } ++ ++ // Complete the request unless we are here as part of unwinding ++ // when an exception condition was encountered, OR ++ // if the request has been deferred (i.e. posted for later handling) ++ if (RC != STATUS_PENDING) ++ { ++ // If we acquired any FCB resources, release them now ... ++ ++ // If any intermediate (directory) open operations were performed, ++ // implement the corresponding close (do *not* however close ++ // the target you have opened on behalf of the caller ...). ++ ++ if (NT_SUCCESS(RC)) ++ { ++ // Update the file object such that: ++ // (a) the FsContext field points to the NTRequiredFCB field ++ // in the FCB ++ // (b) the FsContext2 field points to the CCB created as a ++ // result of the open operation ++ ++ // If write-through was requested, then mark the file object ++ // appropriately ++ if (WriteThroughRequested) ++ { ++ PtrNewFileObject->Flags |= FO_WRITE_THROUGH; ++ } ++ DebugTrace( DEBUG_TRACE_SPECIAL, " === Create/Open successful", 0 ); ++ } ++ else ++ { ++ DebugTrace( DEBUG_TRACE_SPECIAL, " === Create/Open failed", 0 ); ++ // Perform failure related post-processing now ++ } ++ ++ // As long as this unwinding is not being performed as a result of ++ // an exception condition, complete the IRP ... ++ if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) ++ { ++ PtrIrp->IoStatus.Status = RC; ++ PtrIrp->IoStatus.Information = ReturnedInformation; ++ ++ // Free up the Irp Context ++ Ext2ReleaseIrpContext(PtrIrpContext); ++ ++ // complete the IRP ++ IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); ++ } ++ } ++ } ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2OpenVolume() ++* ++* Description: ++* Open a logical volume for the caller. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2OpenVolume( ++PtrExt2VCB PtrVCB, // volume to be opened ++PtrExt2IrpContext PtrIrpContext, // IRP context ++PIRP PtrIrp, // original/user IRP ++unsigned short ShareAccess, // share access ++PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) ++PFILE_OBJECT PtrNewFileObject) // I/O Mgr. created file object ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2CCB PtrCCB = NULL; ++ ++ try { ++ // check for exclusive open requests (using share modes supplied) ++ // and determine whether it is even possible to open the volume ++ // with the specified share modes (e.g. if caller does not ++ // wish to share read or share write ...) ++ ++ // Use IoCheckShareAccess() and IoSetShareAccess() here ... ++ // They are defined in the DDK. ++ ++ // You might also wish to check the caller's security context ++ // to see whether you wish to allow the volume open or not. ++ // Use the SeAccessCheck() routine described in the DDK for this purpose. ++ ++ // create a new CCB structure ++ if (!(PtrCCB = Ext2AllocateCCB())) ++ { ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return(RC); ++ } ++ ++ // initialize the CCB ++ PtrCCB->PtrFCB = (PtrExt2FCB)(PtrVCB); ++ InsertTailList(&(PtrVCB->VolumeOpenListHead), &(PtrCCB->NextCCB)); ++ ++ // initialize the CCB to point to the file object ++ PtrCCB->PtrFileObject = PtrNewFileObject; ++ ++ Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_VOLUME_OPEN); ++ ++ // initialize the file object appropriately ++ PtrNewFileObject->FsContext = (void *)( &(PtrVCB->CommonVCBHeader) ); ++ PtrNewFileObject->FsContext2 = (void *)(PtrCCB); ++ ++ // increment the number of outstanding open operations on this ++ // logical volume (i.e. volume cannot be dismounted) ++ ++ // You might be concerned about 32 bit wrap-around though I would ++ // argue that it is unlikely ... :-) ++ (PtrVCB->VCBOpenCount)++; ++ ++ // now set the IoStatus Information value correctly in the IRP ++ // (caller will set the status field) ++ PtrIrp->IoStatus.Information = FILE_OPENED; ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ NOTHING; ++ } ++ ++ return(RC); ++} ++ ++/************************************************************************* ++* ++* Function: Ext2InitializeFCB() ++* ++* Description: ++* Initialize a new FCB structure and also the sent-in file object ++* (if supplied) ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: None ++* ++************************************************************************* ++void Ext2InitializeFCB( ++PtrExt2FCB PtrNewFCB, // FCB structure to be initialized ++PtrExt2VCB PtrVCB, // logical volume (VCB) pointer ++PtrExt2ObjectName PtrObjectName, // name of the object ++uint32 Flags, // is this a file/directory, etc. ++PFILE_OBJECT PtrFileObject) // optional file object to be initialized ++{ ++ // Initialize the disk dependent portion as you see fit ++ ++ // Initialize the two ERESOURCE objects ++ ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.MainResource)); ++ ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.PagingIoResource)); ++ ++ PtrNewFCB->FCBFlags |= EXT2_INITIALIZED_MAIN_RESOURCE | EXT2_INITIALIZED_PAGING_IO_RESOURCE | Flags; ++ ++ PtrNewFCB->PtrVCB = PtrVCB; ++ ++ // caller MUST ensure that VCB has been acquired exclusively ++ InsertTailList(&(PtrVCB->FCBListHead), &(PtrNewFCB->NextFCB)); ++ ++ // initialize the various list heads ++ InitializeListHead(&(PtrNewFCB->CCBListHead)); ++ ++// PtrNewFCB->ReferenceCount = 1; ++// PtrNewFCB->OpenHandleCount = 1; ++ ++ if( PtrObjectName ) ++ { ++ PtrNewFCB->FCBName = PtrObjectName; ++ } ++ ++ if ( PtrFileObject ) ++ { ++ PtrFileObject->FsContext = (void *)(&(PtrNewFCB->NTRequiredFCB)); ++ } ++ ++ return; ++} ++*/ ++ ++/************************************************************************* ++* ++* Function: Ext2OpenRootDirectory() ++* ++* Description: ++* Open the root directory for a volume ++* ++* ++* Expected Interrupt Level (for execution) : ++* ++* ??? ++* ++* Return Value: None ++* ++*************************************************************************/ ++NTSTATUS Ext2OpenRootDirectory( ++ PtrExt2VCB PtrVCB, // volume ++ PtrExt2IrpContext PtrIrpContext, // IRP context ++ PIRP PtrIrp, // original/user IRP ++ unsigned short ShareAccess, // share access ++ PIO_SECURITY_CONTEXT PtrSecurityContext, // caller's context (incl access) ++ PFILE_OBJECT PtrNewFileObject // I/O Mgr. created file object ++ ) ++{ ++ // Declerations... ++ PtrExt2CCB PtrCCB; ++ ++ ASSERT( PtrVCB ); ++ ASSERT( PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); ++ ASSERT( PtrVCB->PtrRootDirectoryFCB ); ++ AssertFCB( PtrVCB->PtrRootDirectoryFCB ); ++ ++ PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO; ++ ++ // Create a new CCB... ++ Ext2CreateNewCCB( &PtrCCB, PtrVCB->PtrRootDirectoryFCB, PtrNewFileObject); ++ PtrNewFileObject->FsContext = (void *) &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader); ++ PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY; ++ PtrNewFileObject->FsContext2 = (void *) PtrCCB; ++ PtrNewFileObject->SectionObjectPointer = &PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject; ++ PtrNewFileObject->Vpb = PtrVCB->PtrVPB; ++ ++ Ext2CopyUnicodeString( &(PtrCCB->AbsolutePathName), &PtrVCB->PtrRootDirectoryFCB->FCBName->ObjectName ); ++ ++ ++ return STATUS_SUCCESS; ++} ++ ++ ++ ++PtrExt2FCB Ext2LocateChildFCBInCore( ++ PtrExt2VCB PtrVCB, ++ PUNICODE_STRING PtrName, ++ ULONG ParentInodeNo ) ++{ ++ ++ PtrExt2FCB PtrFCB = NULL; ++ ULONG InodeNo = 0; ++ PLIST_ENTRY PtrEntry; ++ ++ if( IsListEmpty( &(PtrVCB->FCBListHead) ) ) ++ { ++ return NULL; // Failure; ++ } ++ ++ for( PtrEntry = PtrVCB->FCBListHead.Flink; ++ PtrEntry != &PtrVCB->FCBListHead; ++ PtrEntry = PtrEntry->Flink ) ++ { ++ PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB ); ++ ASSERT( PtrFCB ); ++ if( PtrFCB->ParentINodeNo == ParentInodeNo ) ++ { ++ if( RtlCompareUnicodeString( &PtrFCB->FCBName->ObjectName, PtrName, TRUE ) == 0 ) ++ return PtrFCB; ++ } ++ } ++ ++ return NULL; ++} ++ ++PtrExt2FCB Ext2LocateFCBInCore( ++ PtrExt2VCB PtrVCB, ++ ULONG InodeNo ) ++{ ++ PtrExt2FCB PtrFCB = NULL; ++ PLIST_ENTRY PtrEntry; ++ ++ if( IsListEmpty( &(PtrVCB->FCBListHead) ) ) ++ { ++ return NULL; // Failure; ++ } ++ ++ for( PtrEntry = PtrVCB->FCBListHead.Flink; ++ PtrEntry != &PtrVCB->FCBListHead; ++ PtrEntry = PtrEntry->Flink ) ++ { ++ PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB ); ++ ASSERT( PtrFCB ); ++ if( PtrFCB->INodeNo == InodeNo ) ++ { ++ return PtrFCB; ++ } ++ } ++ ++ return NULL; ++} ++ ++ ++ULONG Ext2LocateFileInDisk ( ++ PtrExt2VCB PtrVCB, ++ PUNICODE_STRING PtrCurrentName, ++ PtrExt2FCB PtrParentFCB, ++ ULONG *Type ) ++{ ++ ++ PtrExt2FCB PtrNewFCB = NULL; ++ PFILE_OBJECT PtrFileObject = NULL; ++ ULONG InodeNo = 0; ++ ++ *Type = EXT2_FT_UNKNOWN; ++ ++ // 1. ++ // Initialize the Blocks in the FCB... ++ // ++ Ext2InitializeFCBInodeInfo( PtrParentFCB ); ++ ++ ++ // 2. ++ // Is there a file object I can use for caching?? ++ // If not create one... ++ // ++ if( !PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject ) ++ { ++ // ++ // No Directory File Object? ++ // No problem, will create one... ++ // ++ ++ // Acquire the MainResource first though... ++ ++ PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject = IoCreateStreamFileObject(NULL, PtrVCB->TargetDeviceObject ); ++ PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; ++ ++ if( !PtrFileObject ) ++ { ++ Ext2BreakPoint(); ++ return 0; ++ } ++ PtrFileObject->ReadAccess = TRUE; ++ PtrFileObject->WriteAccess = TRUE; ++ ++ // Associate the file stream with the Volume parameter block... ++ PtrFileObject->Vpb = PtrVCB->PtrVPB; ++ ++ // No caching as yet... ++ PtrFileObject->PrivateCacheMap = NULL; ++ ++ // this establishes the FCB - File Object connection... ++ PtrFileObject->FsContext = (void *)( & (PtrParentFCB->NTRequiredFCB.CommonFCBHeader) ); ++ ++ // Initialize the section object pointer... ++ PtrFileObject->SectionObjectPointer = &(PtrParentFCB->NTRequiredFCB.SectionObject); ++ } ++ else ++ { ++ // ++ // I do have a file object... ++ // I am using it now! ++ // ++ PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; ++ } ++ ++ // 3. ++ // Got hold of a file object? Good ;) ++ // Now initiating Caching, pinned access to be precise ... ++ // ++ if (PtrFileObject->PrivateCacheMap == NULL) ++ { ++ CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), ++ TRUE, // We utilize pin access for directories ++ &(Ext2GlobalData.CacheMgrCallBacks), // callbacks ++ PtrParentFCB ); // The context used in callbacks ++ } ++ ++ // 4. ++ // Getting down to the real business now... ;) ++ // Read in the directory contents and do a search ++ // a sequential search to be precise... ++ // Wish Mm'm Renuga were reading this ++ // Would feel proud... ;) ++ // ++ { ++ LARGE_INTEGER StartBufferOffset; ++ ULONG PinBufferLength; ++ ULONG BufferIndex; ++ PBCB PtrBCB = NULL; ++ BYTE * PtrPinnedBlockBuffer = NULL; ++ PEXT2_DIR_ENTRY PtrDirEntry = NULL; ++ BOOLEAN Found; ++ int i; ++ ++ ++ StartBufferOffset.QuadPart = 0; ++ ++ // ++ // Read in the whole damn directory ++ // **Bad programming** ++ // Will do for now. ++ // ++ PinBufferLength = PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; ++ if (!CcMapData( PtrFileObject, ++ &StartBufferOffset, ++ PinBufferLength, ++ TRUE, ++ &PtrBCB, ++ (PVOID*)&PtrPinnedBlockBuffer ) ) ++ { ++ ++ ++ } ++ // ++ // Walking through now... ++ // ++ ++ for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) ++ { ++ PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; ++ if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 || PtrDirEntry->inode == 0) ++ { ++ // Invalid entry... ++ // Ignore... ++ continue; ++ } ++ // ++ // Comparing ( case sensitive ) ++ // Directory entry is not NULL terminated... ++ // nor is the CurrentName... ++ // ++ if( PtrDirEntry->name_len != (PtrCurrentName->Length / 2) ) ++ continue; ++ ++ for( i = 0, Found = TRUE ; i < PtrDirEntry->name_len ; i++ ) ++ { ++ if( PtrDirEntry->name[ i ] != PtrCurrentName->Buffer[ i ] ) ++ { ++ Found = FALSE; ++ break; ++ ++ } ++ } ++ ++ } ++ if( Found ) ++ { ++ InodeNo = PtrDirEntry->inode; ++ ++ if( PtrDirEntry->file_type == EXT2_FT_UNKNOWN ) ++ { ++ ++ // Old Fashioned Directory entries... ++ // Will have to read in the Inode to determine the File Type... ++ EXT2_INODE Inode; ++ // PtrInode = Ext2AllocatePool( NonPagedPool, sizeof( EXT2_INODE ) ); ++ Ext2ReadInode( PtrVCB, InodeNo, &Inode ); ++ ++ if( Ext2IsModeRegularFile( Inode.i_mode ) ) ++ { ++ *Type = EXT2_FT_REG_FILE; ++ } ++ else if ( Ext2IsModeDirectory( Inode.i_mode) ) ++ { ++ // Directory... ++ *Type = EXT2_FT_DIR; ++ } ++ else if( Ext2IsModeSymbolicLink(Inode.i_mode) ) ++ { ++ *Type = EXT2_FT_SYMLINK; ++ } ++ else if( Ext2IsModePipe(Inode.i_mode) ) ++ { ++ *Type = EXT2_FT_FIFO; ++ } ++ else if( Ext2IsModeCharacterDevice(Inode.i_mode) ) ++ { ++ *Type = EXT2_FT_CHRDEV; ++ } ++ else if( Ext2IsModeBlockDevice(Inode.i_mode) ) ++ { ++ *Type = EXT2_FT_BLKDEV; ++ } ++ else if( Ext2IsModeSocket(Inode.i_mode) ) ++ { ++ *Type = EXT2_FT_SOCK; ++ } ++ else ++ { ++ *Type = EXT2_FT_UNKNOWN; ++ } ++ ++ //DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Create]", PtrInode ); ++ //ExFreePool( PtrInode ); ++ } ++ else ++ { ++ *Type = PtrDirEntry->file_type; ++ } ++ } ++ ++ CcUnpinData( PtrBCB ); ++ PtrBCB = NULL; ++ ++ return InodeNo; ++ } ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2CreateFile() ++* ++* Description: ++* Creates a new file on the disk ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Restrictions: ++* Expects the VCB to be acquired Exclusively before being invoked ++* ++* Return Value: None ++* ++*************************************************************************/ ++ULONG Ext2CreateFile( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ PUNICODE_STRING PtrName, ++ PtrExt2FCB PtrParentFCB, ++ ULONG Type) ++{ ++ EXT2_INODE Inode, ParentInode; ++ ++ ULONG NewInodeNo = 0; ++ BOOLEAN FCBAcquired = FALSE; ++ ++ ULONG LogicalBlockSize = 0; ++ ++ try ++ { ++ ++ ++ // 0. Verify if the creation is possible,,, ++ if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE ) ++ { ++ // ++ // Can create only a directory or a regular file... ++ // ++ return 0; ++ } ++ ++ // 1. Allocate an i-node... ++ ++ NewInodeNo = Ext2AllocInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo ); ++ ++ // NewInodeNo = 12; ++ ++ if( !NewInodeNo ) ++ { ++ return 0; ++ } ++ ++ // 2. Acquire the Parent FCB Exclusively... ++ if( !ExAcquireResourceExclusiveLite(&( PtrParentFCB->NTRequiredFCB.MainResource ), TRUE) ) ++ { ++ Ext2DeallocInode( PtrIrpContext, PtrVCB, NewInodeNo ); ++ try_return( NewInodeNo = 0); ++ } ++ FCBAcquired = TRUE; ++ ++ // 3. Make an entry in the parent Directory... ++ ASSERT( PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject ); ++ ++ Ext2MakeNewDirectoryEntry( ++ PtrIrpContext, ++ PtrParentFCB, ++ PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject, ++ PtrName, Type, NewInodeNo ); ++ ++ ++ // 4. Initialize an inode entry and write it to disk... ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ { ++ // To be deleted ++ Ext2ReadInode( PtrVCB, NewInodeNo, &Inode ); ++ } ++ ++ RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) ); ++ if( Type == EXT2_FT_DIR ) ++ { ++ Inode.i_mode = 0x41ff; ++ ++ // In addition to the usual link, ++ // there will be an additional link in the directory itself - the '.' entry ++ Inode.i_links_count = 2; ++ ++ // Incrementing the link count for the parent as well... ++ Ext2ReadInode( PtrVCB, PtrParentFCB->INodeNo, &ParentInode ); ++ ParentInode.i_links_count++; ++ Ext2WriteInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo, &ParentInode ); ++ ++ } ++ else ++ { ++ Inode.i_mode = 0x81ff; ++ Inode.i_links_count = 1; ++ } ++ ++ ++ { ++ // ++ // Setting the time fields in the inode... ++ // ++ ULONG Time; ++ Time = Ext2GetCurrentTime(); ++ Inode.i_ctime = Time; ++ Inode.i_atime = Time; ++ Inode.i_mtime = Time; ++ Inode.i_dtime = 0; // Deleted time; ++ } ++ ++ Ext2WriteInode( PtrIrpContext, PtrVCB, NewInodeNo, &Inode ); ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( FCBAcquired ) ++ { ++ Ext2ReleaseResource( &(PtrParentFCB->NTRequiredFCB.MainResource) ); ++ } ++ } ++ ++ return NewInodeNo ; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2CreateFile() ++* ++* Description: ++* Overwrites an existing file on the disk ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Restrictions: ++* Expects the VCB to be acquired Exclusively before being invoked ++* ++* Return Value: None ++* ++*************************************************************************/ ++BOOLEAN Ext2OverwriteFile( ++ PtrExt2FCB PtrFCB, ++ PtrExt2IrpContext PtrIrpContext) ++{ ++ EXT2_INODE Inode; ++ PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; ++ ULONG i; ++ ULONG Time; ++ Time = Ext2GetCurrentTime(); ++ ++ Ext2InitializeFCBInodeInfo( PtrFCB ); ++ // 1. ++ // Update the inode... ++ if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ return FALSE; ++ } ++ ++ Inode.i_size = 0; ++ Inode.i_blocks = 0; ++ Inode.i_atime = Time; ++ Inode.i_mtime = Time; ++ Inode.i_dtime = 0; ++ ++ for( i = 0; i < EXT2_N_BLOCKS; i++ ) ++ { ++ Inode.i_block[ i ] = 0; ++ } ++ ++ if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ return FALSE; ++ } ++ ++ // 2. ++ // Release all the data blocks... ++ if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) ) ++ { ++ return FALSE; ++ } ++ ++ Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); ++ Ext2InitializeFCBInodeInfo( PtrFCB ); ++ ++ return TRUE; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2SupersedeFile() ++* ++* Description: ++* Supersedes an existing file on the disk ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Restrictions: ++* Expects the VCB to be acquired Exclusively before being invoked ++* ++* Return Value: None ++* ++*************************************************************************/ ++BOOLEAN Ext2SupersedeFile( ++ PtrExt2FCB PtrFCB, ++ PtrExt2IrpContext PtrIrpContext) ++{ ++ EXT2_INODE Inode; ++ PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; ++ ULONG i; ++ ++ Ext2InitializeFCBInodeInfo( PtrFCB ); ++ ++ // 1. ++ // Initialize the inode... ++ RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) ); ++ ++ // Setting the file mode... ++ // This operation is allowed only for a regular file... ++ Inode.i_mode = 0x81ff; ++ ++ // Maintaining the old link count... ++ Inode.i_links_count = PtrFCB->LinkCount; ++ ++ // Setting the time fields in the inode... ++ { ++ ULONG Time; ++ Time = Ext2GetCurrentTime(); ++ Inode.i_ctime = Time; ++ Inode.i_atime = Time; ++ Inode.i_mtime = Time; ++ Inode.i_dtime = 0; // Deleted time; ++ } ++ ++ if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ return FALSE; ++ } ++ ++ // 2. ++ // Release all the data blocks... ++ if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) ) ++ { ++ return FALSE; ++ } ++ ++ Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); ++ Ext2InitializeFCBInodeInfo( PtrFCB ); ++ ++ return TRUE; ++} diff --cc reactos/drivers/filesystems/ext2/src/devcntrl.c index 00000000000,00000000000..02389865f6c new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/devcntrl.c @@@ -1,0 -1,0 +1,210 @@@ ++/************************************************************************* ++* ++* File: devcntrl.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains code to handle the "Device IOCTL" dispatch entry point. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_DEVICE_CONTROL ++#define DEBUG_LEVEL DEBUG_TRACE_DEVCTRL ++ ++ ++#if(_WIN32_WINNT < 0x0400) ++#define IOCTL_REDIR_QUERY_PATH CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 99, METHOD_NEITHER, FILE_ANY_ACCESS) ++ ++typedef struct _QUERY_PATH_REQUEST ++{ ++ ULONG PathNameLength; ++ PIO_SECURITY_CONTEXT SecurityContext; ++ WCHAR FilePathName[1]; ++} QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST; ++ ++typedef struct _QUERY_PATH_RESPONSE ++{ ++ ULONG LengthAccepted; ++} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE; ++#endif ++ ++ ++/************************************************************************* ++* ++* Function: Ext2DeviceControl() ++* ++* Description: ++* The I/O Manager will invoke this routine to handle a Device IOCTL ++* request ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution ++* to be deferred to a worker thread context) ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2DeviceControl( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp) // I/O Request Packet ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ BOOLEAN AreWeTopLevel = FALSE; ++ ++ // Ext2BreakPoint(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Device Control IRP Received...", 0); ++ ++ FsRtlEnterFileSystem(); ++ ASSERT(DeviceObject); ++ ASSERT(Irp); ++ ++ // set the top level context ++ AreWeTopLevel = Ext2IsIrpTopLevel(Irp); ++ ++ try { ++ ++ // get an IRP context structure and issue the request ++ PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); ++ ASSERT(PtrIrpContext); ++ ++ RC = Ext2CommonDeviceControl(PtrIrpContext, Irp); ++ ++ } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, Irp); ++ ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ if (AreWeTopLevel) { ++ IoSetTopLevelIrp(NULL); ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2CommonDeviceControl() ++* ++* Description: ++* The actual work is performed here. This routine may be invoked in one' ++* of the two possible contexts: ++* (a) in the context of a system worker thread ++* (b) in the context of the original caller ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2CommonDeviceControl( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PIO_STACK_LOCATION PtrIoStackLocation = NULL; ++ PIO_STACK_LOCATION PtrNextIoStackLocation = NULL; ++ PFILE_OBJECT PtrFileObject = NULL; ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2VCB PtrVCB = NULL; ++ ULONG IoControlCode = 0; ++ void *BufferPointer = NULL; ++ ++ try ++ { ++ // First, get a pointer to the current I/O stack location ++ PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ++ ASSERT(PtrIoStackLocation); ++ ++ PtrFileObject = PtrIoStackLocation->FileObject; ++ ASSERT(PtrFileObject); ++ ++ PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2); ++ ASSERT(PtrCCB); ++ PtrFCB = PtrCCB->PtrFCB; ++ ASSERT(PtrFCB); ++ ++ ++ if( PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) ++ { ++ PtrVCB = (PtrExt2VCB)(PtrFCB); ++ } ++ else ++ { ++ AssertFCB( PtrFCB ); ++ ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB); ++ PtrVCB = PtrFCB->PtrVCB; ++ } ++ ++ // Get the IoControlCode value ++ IoControlCode = PtrIoStackLocation->Parameters.DeviceIoControl.IoControlCode; ++ ++ // You may wish to allow only volume open operations. ++ ++ // Invoke the lower level driver in the chain. ++ PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp); ++ *PtrNextIoStackLocation = *PtrIoStackLocation; ++ // Set a completion routine. ++ IoSetCompletionRoutine(PtrIrp, Ext2DevIoctlCompletion, NULL, TRUE, TRUE, TRUE); ++ // Send the request. ++ RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ // Release the IRP context ++ if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) ++ { ++ // Free up the Irp Context ++ Ext2ReleaseIrpContext(PtrIrpContext); ++ } ++ } ++ ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2DevIoctlCompletion() ++* ++* Description: ++* Completion routine. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS ++* ++*************************************************************************/ ++NTSTATUS Ext2DevIoctlCompletion( ++PDEVICE_OBJECT PtrDeviceObject, ++PIRP PtrIrp, ++void *Context) ++{ ++ if (PtrIrp->PendingReturned) { ++ IoMarkIrpPending(PtrIrp); ++ } ++ ++ return(STATUS_SUCCESS); ++} diff --cc reactos/drivers/filesystems/ext2/src/dircntrl.c index 00000000000,759f2c25212..759f2c25212 mode 000000,100644..100644 --- a/reactos/drivers/filesystems/ext2/src/dircntrl.c +++ b/reactos/drivers/filesystems/ext2/src/dircntrl.c diff --cc reactos/drivers/filesystems/ext2/src/ext2.rc index 00000000000,00000000000..cadc35f7d0c new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/ext2.rc @@@ -1,0 -1,0 +1,116 @@@ ++//Microsoft Developer Studio generated resource script. ++// ++#include "../inc/resource.h" ++ ++#define APSTUDIO_READONLY_SYMBOLS ++///////////////////////////////////////////////////////////////////////////// ++// ++// Generated from the TEXTINCLUDE 2 resource. ++// ++#define APSTUDIO_HIDDEN_SYMBOLS ++#include "windows.h" ++#undef APSTUDIO_HIDDEN_SYMBOLS ++/* REACTOS FIXME */ ++/* #include "ntverp.h" */ ++ ++///////////////////////////////////////////////////////////////////////////// ++#undef APSTUDIO_READONLY_SYMBOLS ++ ++///////////////////////////////////////////////////////////////////////////// ++// English (U.S.) resources ++ ++#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) ++#ifdef _WIN32 ++LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US ++#pragma code_page(1252) ++#endif //_WIN32 ++ ++#ifdef APSTUDIO_INVOKED ++///////////////////////////////////////////////////////////////////////////// ++// ++// TEXTINCLUDE ++// ++ ++1 TEXTINCLUDE DISCARDABLE ++BEGIN ++ "..\\inc\\resource.h\0" ++END ++ ++2 TEXTINCLUDE DISCARDABLE ++BEGIN ++ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" ++ "#include ""windows.h""\r\n" ++ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" ++ "#include ""ntverp.h""\r\n" ++ "\0" ++END ++ ++3 TEXTINCLUDE DISCARDABLE ++BEGIN ++ "\r\n" ++ "\0" ++END ++ ++#endif // APSTUDIO_INVOKED ++ ++ ++#ifndef _MAC ++///////////////////////////////////////////////////////////////////////////// ++// ++// Version ++// ++ ++VS_VERSION_INFO VERSIONINFO ++ FILEVERSION 0,0,0,3 ++ PRODUCTVERSION 0,0,0,3 ++ FILEFLAGSMASK 0x3fL ++#ifdef _DEBUG ++ FILEFLAGS 0x29L ++#else ++ FILEFLAGS 0x28L ++#endif ++ FILEOS 0x40004L ++ FILETYPE 0x3L ++ FILESUBTYPE 0x7L ++BEGIN ++ BLOCK "StringFileInfo" ++ BEGIN ++ BLOCK "040904b0" ++ BEGIN ++ VALUE "Comments", "Ext2 File System Driver\0" ++ VALUE "CompanyName", "Purayidathil\0" ++ VALUE "FileDescription", "Ext2 File System Driver\0" ++ VALUE "FileVersion", "0, 0, 0, 3\0" ++ VALUE "InternalName", "ext2.sys\0" ++ VALUE "LegalCopyright", "Copyright © 2002 Manoj Paul Joseph\0" ++ VALUE "LegalTrademarks", " - \0" ++ VALUE "OriginalFilename", "ext2.sys\0" ++ VALUE "PrivateBuild", " - \0" ++ VALUE "ProductName", "Ext2 File System Driver for Windows NT\0" ++ VALUE "ProductVersion", "0, 0, 0, 3\0" ++ VALUE "SpecialBuild", " - \0" ++ END ++ END ++ BLOCK "VarFileInfo" ++ BEGIN ++ VALUE "Translation", 0x409, 1200 ++ END ++END ++ ++#endif // !_MAC ++ ++#endif // English (U.S.) resources ++///////////////////////////////////////////////////////////////////////////// ++ ++ ++ ++#ifndef APSTUDIO_INVOKED ++///////////////////////////////////////////////////////////////////////////// ++// ++// Generated from the TEXTINCLUDE 3 resource. ++// ++ ++ ++///////////////////////////////////////////////////////////////////////////// ++#endif // not APSTUDIO_INVOKED ++ diff --cc reactos/drivers/filesystems/ext2/src/ext2init.c index 00000000000,00000000000..3df67efc60f new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/ext2init.c @@@ -1,0 -1,0 +1,381 @@@ ++/************************************************************************* ++* ++* File: ext2init.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* This file contains the initialization code for the kernel mode ++* Ext2 FSD module. The DriverEntry() routine is called by the I/O ++* sub-system to initialize the FSD. ++* ++* Author: Manoj Paul Joseph ++* ++*************************************************************************/ ++ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_INIT ++#define DEBUG_LEVEL (DEBUG_TRACE_INIT) ++ ++#define EXT2_FS_NAME L"\\ext2" ++ ++// global variables are declared here ++Ext2Data Ext2GlobalData; ++ ++ ++/************************************************************************* ++* ++* Function: DriverEntry() ++* ++* Description: ++* This routine is the standard entry point for all kernel mode drivers. ++* The routine is invoked at IRQL PASSIVE_LEVEL in the context of a ++* system worker thread. ++* All FSD specific data structures etc. are initialized here. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error (will cause driver to be unloaded). ++* ++*************************************************************************/ ++NTSTATUS DriverEntry( ++PDRIVER_OBJECT DriverObject, // created by the I/O sub-system ++PUNICODE_STRING RegistryPath) // path to the registry key ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ UNICODE_STRING DriverDeviceName; ++ BOOLEAN RegisteredShutdown = FALSE; ++ ++#if 0 ++ Ext2BreakPoint(); ++#endif ++ ++ try ++ { ++ try ++ { ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Ext2 File System Driver Entry <<<<<<<", 0); ++ // initialize the global data structure ++ RtlZeroMemory(&Ext2GlobalData, sizeof(Ext2GlobalData)); ++ ++ // initialize some required fields ++ Ext2GlobalData.NodeIdentifier.NodeType = EXT2_NODE_TYPE_GLOBAL_DATA; ++ Ext2GlobalData.NodeIdentifier.NodeSize = sizeof(Ext2GlobalData); ++ ++ // initialize the global data resource and remember the fact that ++ // the resource has been initialized ++ RC = ExInitializeResourceLite(&(Ext2GlobalData.GlobalDataResource)); ++ ASSERT(NT_SUCCESS(RC)); ++ Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_RESOURCE_INITIALIZED); ++ ++ // keep a ptr to the driver object sent to us by the I/O Mgr ++ Ext2GlobalData.Ext2DriverObject = DriverObject; ++ ++ // initialize the mounted logical volume list head ++ InitializeListHead( &( Ext2GlobalData.NextVCB ) ); ++ ++ // before we proceed with any more initialization, read in ++ // user supplied configurable values ... ++ // if (!NT_SUCCESS(RC = Ext2ObtainRegistryValues(RegistryPath))) { ++ // in your commercial driver implementation, it would be ++ // advisable for your driver to print an appropriate error ++ // message to the system error log before leaving ++ // try_return(RC); ++ // } ++ ++ // we should have the registry data (if any), allocate zone memory ... ++ // This is an example of when FSD implementations try to pre-allocate ++ // some fixed amount of memory to avoid internal fragmentation and/or waiting ++ // later during run-time ... ++ ++#ifdef USE_ZONES ++ ++ if (!NT_SUCCESS(RC = Ext2InitializeZones())) ++ { ++ // we failed, print a message and leave ... ++ try_return(RC); ++ } ++#endif ++ ++ // ++ // Initialize the Thread queue structure... ++ // ++ KeInitializeEvent( ++ &Ext2GlobalData.ThreadQueue.QueueEvent, ++ SynchronizationEvent, ++ FALSE ++ ); ++ KeInitializeSpinLock( &Ext2GlobalData.ThreadQueue.SpinLock ); ++ InitializeListHead( &Ext2GlobalData.ThreadQueue.ThreadQueueListHead ); ++ ++ // ++ // Done Initializing... ++ // Now Creating a worker thread to handle Worker threads... ++ // ++ PsCreateSystemThread( ++ &Ext2GlobalData.ThreadQueue.QueueHandlerThread, (ACCESS_MASK) 0L, ++ NULL, NULL, NULL, Ext2QueueHandlerThread, NULL ); ++ ++ // initialize the IRP major function table, and the fast I/O table ++ Ext2FsdInitializeFunctionPointers(DriverObject); ++ ++ // create a device object representing the driver itself ++ // so that requests can be targeted to the driver ... ++ // e.g. for a disk-based FSD, "mount" requests will be sent to ++ // this device object by the I/O Manager.\ ++ // For a redirector/server, you may have applications ++ // send "special" IOCTL's using this device object ... ++ RtlInitUnicodeString(&DriverDeviceName, EXT2_FS_NAME); ++ if (!NT_SUCCESS(RC = IoCreateDevice( ++ DriverObject, // our driver object ++ 0, // don't need an extension for this object ++ &DriverDeviceName,// name - can be used to "open" the driver ++ // see the book for alternate choices ++ FILE_DEVICE_DISK_FILE_SYSTEM, ++ 0, // no special characteristics ++ // do not want this as an exclusive device, though you might ++ FALSE, ++ &(Ext2GlobalData.Ext2DeviceObject)))) ++ { ++ // failed to create a device object, leave ... ++ try_return(RC); ++ } ++ ++ ++ ++ // register the driver with the I/O Manager, pretend as if this is ++ // a physical disk based FSD (or in order words, this FSD manages ++ // logical volumes residing on physical disk drives) ++ IoRegisterFileSystem(Ext2GlobalData.Ext2DeviceObject); ++ ++ { ++ TIME_FIELDS TimeFields; ++ ++ TimeFields.Day = 1; ++ TimeFields.Hour = 0; ++ TimeFields.Milliseconds = 0; ++ TimeFields.Minute = 0; ++ TimeFields.Month = 1; ++ TimeFields.Second = 0; ++ TimeFields.Weekday = 0; ++ TimeFields.Year = 1970; ++ RtlTimeFieldsToTime( &TimeFields, &Ext2GlobalData.TimeDiff ); ++ ++ /* ++ Ext2GlobalData.TimeDiff.QuadPart = 0; ++ RtlTimeToTimeFields( &Ext2GlobalData.TimeDiff,&TimeFields ); ++ TimeFields.Year = 2002; ++ RtlTimeFieldsToTime( &TimeFields, &Ext2GlobalData.TimeDiff ); ++ */ ++ ++ } ++ } ++ except (EXCEPTION_EXECUTE_HANDLER) ++ { ++ // we encountered an exception somewhere, eat it up ++ RC = GetExceptionCode(); ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ // start unwinding if we were unsuccessful ++ if (!NT_SUCCESS(RC)) ++ { ++ ++ // Now, delete any device objects, etc. we may have created ++ if (Ext2GlobalData.Ext2DeviceObject) ++ { ++ IoDeleteDevice(Ext2GlobalData.Ext2DeviceObject); ++ Ext2GlobalData.Ext2DeviceObject = NULL; ++ } ++ ++ // free up any memory we might have reserved for zones/lookaside ++ // lists ++ if (Ext2GlobalData.Ext2Flags & EXT2_DATA_FLAGS_ZONES_INITIALIZED) ++ { ++ Ext2DestroyZones(); ++ } ++ ++ // delete the resource we may have initialized ++ if (Ext2GlobalData.Ext2Flags & EXT2_DATA_FLAGS_RESOURCE_INITIALIZED) ++ { ++ // un-initialize this resource ++ ExDeleteResourceLite(&(Ext2GlobalData.GlobalDataResource)); ++ Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_RESOURCE_INITIALIZED); ++ } ++ } ++ } ++ ++ return(RC); ++} ++ ++/************************************************************************* ++* ++* Function: Ext2FsdInitializeFunctionPointers() ++* ++* Description: ++* Initialize the IRP... function pointer array in the driver object ++* structure. Also initialize the fast-io function ptr array ... ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: None ++* ++*************************************************************************/ ++void Ext2FsdInitializeFunctionPointers( ++PDRIVER_OBJECT DriverObject) // created by the I/O sub-system ++{ ++ PFAST_IO_DISPATCH PtrFastIoDispatch = NULL; ++ ++ // initialize the function pointers for the IRP major ++ // functions that this FSD is prepared to handle ... ++ // NT Version 4.0 has 28 possible functions that a ++ // kernel mode driver can handle. ++ // NT Version 3.51 and before has only 22 such functions, ++ // of which 18 are typically interesting to most FSD's. ++ ++ // The only interesting new functions that a FSD might ++ // want to respond to beginning with Version 4.0 are the ++ // IRP_MJ_QUERY_QUOTA and the IRP_MJ_SET_QUOTA requests. ++ ++ // The code below does not handle quota manipulation, neither ++ // does the NT Version 4.0 operating system (or I/O Manager). ++ // However, you should be on the lookout for any such new ++ // functionality that your FSD might have to implement in ++ // the near future. ++ ++ DriverObject->MajorFunction[IRP_MJ_CREATE] = Ext2Create; ++ DriverObject->MajorFunction[IRP_MJ_CLOSE] = Ext2Close; ++ DriverObject->MajorFunction[IRP_MJ_READ] = Ext2Read; ++ DriverObject->MajorFunction[IRP_MJ_WRITE] = Ext2Write; ++ ++ DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = Ext2FileInfo; ++ DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = Ext2FileInfo; ++ ++ DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = Ext2Flush; ++ // To implement support for querying and modifying volume attributes ++ // (volume information query/set operations), enable initialization ++ // of the following two function pointers and then implement the supporting ++ // functions. Use Chapter 11 in the text to assist you in your efforts. ++ DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = Ext2QueryVolInfo; ++ DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = Ext2SetVolInfo; ++ DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = Ext2DirControl; ++ // To implement support for file system IOCTL calls, enable initialization ++ // of the following function pointer and implement appropriate support. Use ++ // Chapter 11 in the text to assist you in your efforts. ++ DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = Ext2FileSystemControl; ++ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Ext2DeviceControl; ++ DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = Ext2Shutdown; ++ // For byte-range lock support, enable initialization of the following ++ // function pointer and implement appropriate support. Use Chapter 10 ++ // in the text to assist you in your efforts. ++ // DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = Ext2LockControl; ++ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = Ext2Cleanup; ++ // If your FSD supports security attributes, you should provide appropriate ++ // dispatch entry points and initialize the function pointers as given below. ++ // DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = Ext2Security; ++ // DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = Ext2Security; ++ // If you support extended attributes, you should provide appropriate ++ // dispatch entry points and initialize the function pointers as given below. ++ // DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = Ext2ExtendedAttr; ++ // DriverObject->MajorFunction[IRP_MJ_SET_EA] = Ext2ExtendedAttr; ++ ++ // Now, it is time to initialize the fast-io stuff ... ++/* ++ DriverObject->FastIoDispatch = NULL; ++ ++*/ ++ PtrFastIoDispatch = DriverObject->FastIoDispatch = &(Ext2GlobalData.Ext2FastIoDispatch); ++ ++ // initialize the global fast-io structure ++ // NOTE: The fast-io structure has undergone a substantial revision ++ // in Windows NT Version 4.0. The structure has been extensively expanded. ++ // Therefore, if your driver needs to work on both V3.51 and V4.0+, ++ // you will have to be able to distinguish between the two versions at compile time. ++ PtrFastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); ++ PtrFastIoDispatch->FastIoCheckIfPossible = Ext2FastIoCheckIfPossible; ++ PtrFastIoDispatch->FastIoRead = Ext2FastIoRead; ++ PtrFastIoDispatch->FastIoWrite = Ext2FastIoWrite; ++ PtrFastIoDispatch->FastIoQueryBasicInfo = Ext2FastIoQueryBasicInfo; ++ PtrFastIoDispatch->FastIoQueryStandardInfo = Ext2FastIoQueryStdInfo; ++ PtrFastIoDispatch->FastIoLock = Ext2FastIoLock; ++ PtrFastIoDispatch->FastIoUnlockSingle = Ext2FastIoUnlockSingle; ++ PtrFastIoDispatch->FastIoUnlockAll = Ext2FastIoUnlockAll; ++ PtrFastIoDispatch->FastIoUnlockAllByKey = Ext2FastIoUnlockAllByKey; ++ PtrFastIoDispatch->AcquireFileForNtCreateSection = Ext2FastIoAcqCreateSec; ++ PtrFastIoDispatch->ReleaseFileForNtCreateSection = Ext2FastIoRelCreateSec; ++ ++ // the remaining are only valid under NT Version 4.0 and later ++#if(_WIN32_WINNT >= 0x0400) ++ PtrFastIoDispatch->FastIoQueryNetworkOpenInfo = Ext2FastIoQueryNetInfo; ++ PtrFastIoDispatch->AcquireForModWrite = Ext2FastIoAcqModWrite; ++ PtrFastIoDispatch->ReleaseForModWrite = Ext2FastIoRelModWrite; ++ PtrFastIoDispatch->AcquireForCcFlush = Ext2FastIoAcqCcFlush; ++ PtrFastIoDispatch->ReleaseForCcFlush = Ext2FastIoRelCcFlush; ++ ++ // MDL functionality ++ PtrFastIoDispatch->MdlRead = Ext2FastIoMdlRead; ++ PtrFastIoDispatch->MdlReadComplete = Ext2FastIoMdlReadComplete; ++ PtrFastIoDispatch->PrepareMdlWrite = Ext2FastIoPrepareMdlWrite; ++ PtrFastIoDispatch->MdlWriteComplete = Ext2FastIoMdlWriteComplete; ++ ++ // although this FSD does not support compressed read/write functionality, ++ // NTFS does, and if you design a FSD that can provide such functionality, ++ // you should consider initializing the fast io entry points for reading ++ // and/or writing compressed data ... ++#endif // (_WIN32_WINNT >= 0x0400) ++ ++ ++ // last but not least, initialize the Cache Manager callback functions ++ // which are used in CcInitializeCacheMap() ++ Ext2GlobalData.CacheMgrCallBacks.AcquireForLazyWrite = Ext2AcqLazyWrite; ++ Ext2GlobalData.CacheMgrCallBacks.ReleaseFromLazyWrite = Ext2RelLazyWrite; ++ Ext2GlobalData.CacheMgrCallBacks.AcquireForReadAhead = Ext2AcqReadAhead; ++ Ext2GlobalData.CacheMgrCallBacks.ReleaseFromReadAhead = Ext2RelReadAhead; ++ ++ return; ++} ++ ++ ++VOID Ext2QueueHandlerThread( ++ IN PVOID StartContext ) ++{ ++ ++ DebugTrace(DEBUG_TRACE_MISC, "Ext2QueueHandlerThread!!!", 0); ++ ++ while( 1 ) ++ { ++ KeWaitForSingleObject( &Ext2GlobalData.ThreadQueue.QueueEvent, ++ Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); ++ ++ DebugTrace(DEBUG_TRACE_MISC, "Ext2QueueHandlerThread Alerted!!!", 0); ++ ++ while( !IsListEmpty( &Ext2GlobalData.ThreadQueue.ThreadQueueListHead ) ) ++ { ++ HANDLE ThreadHandle; ++ PLIST_ENTRY PtrEntry = NULL; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ ++ PtrEntry = ExInterlockedRemoveHeadList( ++ &Ext2GlobalData.ThreadQueue.ThreadQueueListHead, ++ &Ext2GlobalData.ThreadQueue.SpinLock ); ++ ASSERT( PtrEntry ); ++ PtrIrpContext = CONTAINING_RECORD( PtrEntry, Ext2IrpContext, ThreadQueueListEntry ); ++ ++ PsCreateSystemThread( ++ &ThreadHandle, (ACCESS_MASK) 0L, ++ NULL, NULL, NULL, Ext2CommonDispatch, PtrIrpContext ); ++ } ++ } ++} diff --cc reactos/drivers/filesystems/ext2/src/fastio.c index 00000000000,00000000000..39d87839d92 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/fastio.c @@@ -1,0 -1,0 +1,1757 @@@ ++/************************************************************************* ++* ++* File: fastio.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains code to handle the various "fast-io" calls. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_FAST_IO ++ ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoCheckIfPossible() ++* ++* Description: ++* To fast-io or not to fast-io, that is the question ... ++* This routine helps the I/O Manager determine whether the FSD wishes ++* to permit fast-io on a specific file stream. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoCheckIfPossible( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN BOOLEAN Wait, ++IN ULONG LockKey, ++IN BOOLEAN CheckForReadOperation, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ LARGE_INTEGER IoLength; ++ ++ // Obtain a pointer to the FCB and CCB for the file stream. ++ PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); ++ ASSERT(PtrCCB); ++ PtrFCB = PtrCCB->PtrFCB; ++ ASSERT(PtrFCB); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoCheckIfPossible - Denying", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ AssertFCBorVCB( PtrFCB ); ++ ++/* if( !( PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ++ || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) ) ++ { ++ // Ext2BreakPoint(); ++ DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); ++ ++ return FALSE; ++ } ++*/ ++ ++ return FALSE; ++ ++ // Validate that this is a fast-IO request to a regular file. ++ // The sample FSD for example, will not allow fast-IO requests ++ // to volume objects, or to directories. ++ if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || ++ (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) ++ { ++ // This is not allowed. ++ return(ReturnedStatus); ++ } ++ ++ IoLength = RtlConvertUlongToLargeInteger(Length); ++ ++ // Your FSD can determine the checks that it needs to perform. ++ // Typically, a FSD will check whether there exist any byte-range ++ // locks that would prevent a fast-IO operation from proceeding. ++ ++ // ... (FSD specific checks go here). ++ ++ if (CheckForReadOperation) ++ { ++ // Chapter 11 describes how to use the FSRTL package for byte-range ++ // lock requests. The following routine is exported by the FSRTL ++ // package and it returns TRUE if the read operation should be ++ // allowed to proceed based on the status of the current byte-range ++ // locks on the file stream. If you do not use the FSRTL package ++ // for byte-range locking support, then you must substitute your ++ // own checks over here. ++ // ReturnedStatus = FsRtlFastCheckLockForRead(&(PtrFCB->FCBByteRangeLock), ++ // FileOffset, &IoLength, LockKey, FileObject, ++ // PsGetCurrentProcess()); ++ } ++ else ++ { ++ // This is a write request. Invoke the FSRTL byte-range lock package ++ // to see whether the write should be allowed to proceed. ++ // ReturnedStatus = FsRtlFastCheckLockForWrite(&(PtrFCB->FCBByteRangeLock), ++ // FileOffset, &IoLength, LockKey, FileObject, ++ // PsGetCurrentProcess()); ++ } ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoRead() ++* ++* Description: ++* Bypass the traditional IRP method to perform a read operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoRead( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN BOOLEAN Wait, ++IN ULONG LockKey, ++OUT PVOID Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRead", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ ++ try ++ { ++ ++ try ++ { ++ ++ // Chapter 11 describes how to roll your own fast-IO entry points. ++ // Typically, you will acquire appropriate resources here and ++ // then (maybe) forward the request to FsRtlCopyRead(). ++ // If you are a suitably complex file system, you may even choose ++ // to do some pre-processing (e.g. prefetching data from someplace) ++ // before passing on the request to the FSRTL package. ++ ++ // Of course, you also have the option of bypassing the FSRTL ++ // package completely and simply forwarding the request directly ++ // to the NT Cache Manager. ++ ++ // Bottom line is that you have complete flexibility on determining ++ // what you decide to do here. Read Chapter 11 well (and obviously ++ // other related issues) before filling in this and other fast-IO ++ // dispatch entry points. ++ ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ ++ } ++ ++ try_exit: NOTHING; ++ ++ } finally { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoWrite() ++* ++* Description: ++* Bypass the traditional IRP method to perform a write operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoWrite( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN BOOLEAN Wait, ++IN ULONG LockKey, ++OUT PVOID Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoWrite", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ try ++ { ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoQueryBasicInfo() ++* ++* Description: ++* Bypass the traditional IRP method to perform a query basic ++* information operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoQueryBasicInfo( ++IN PFILE_OBJECT FileObject, ++IN BOOLEAN Wait, ++OUT PFILE_BASIC_INFORMATION Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoQueryBasicInfo", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoQueryStdInfo() ++* ++* Description: ++* Bypass the traditional IRP method to perform a query standard ++* information operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoQueryStdInfo( ++IN PFILE_OBJECT FileObject, ++IN BOOLEAN Wait, ++OUT PFILE_STANDARD_INFORMATION Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoQueryStdInfo", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoLock() ++* ++* Description: ++* Bypass the traditional IRP method to perform a byte range lock ++* operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoLock( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN PLARGE_INTEGER Length, ++PEPROCESS ProcessId, ++ULONG Key, ++BOOLEAN FailImmediately, ++BOOLEAN ExclusiveLock, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoLock", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoUnlockSingle() ++* ++* Description: ++* Bypass the traditional IRP method to perform a byte range unlock ++* operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoUnlockSingle( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN PLARGE_INTEGER Length, ++PEPROCESS ProcessId, ++ULONG Key, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockSingle", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoUnlockAll() ++* ++* Description: ++* Bypass the traditional IRP method to perform multiple byte range unlock ++* operations. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoUnlockAll( ++IN PFILE_OBJECT FileObject, ++PEPROCESS ProcessId, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockAll", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoUnlockAllByKey() ++* ++* Description: ++* Bypass the traditional IRP method to perform multiple byte range unlock ++* operations. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoUnlockAllByKey( ++IN PFILE_OBJECT FileObject, ++PEPROCESS ProcessId, ++ULONG Key, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoUnlockAllByKey", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoAcqCreateSec() ++* ++* Description: ++* Not really a fast-io operation. Used by the VMM to acquire FSD resources ++* before processing a file map (create section object) request. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: None (we must be prepared to handle VMM initiated calls) ++* ++*************************************************************************/ ++void Ext2FastIoAcqCreateSec( ++IN PFILE_OBJECT FileObject) ++{ ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ ++ // Obtain a pointer to the FCB and CCB for the file stream. ++ PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); ++ ASSERT(PtrCCB); ++ PtrFCB = PtrCCB->PtrFCB; ++ ASSERT(PtrFCB); ++ ++ AssertFCB( PtrFCB ); ++ ++/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) ++ { ++ // Ext2BreakPoint(); ++ DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); ++ return; ++ } */ ++ ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoAcqCreateSec", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ // Acquire the MainResource exclusively for the file stream ++ ++ DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [FastIo]", 0); ++ ++ DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ++ ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); ++ ++ DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); ++ ++ // Although this is typically not required, the sample FSD will ++ // also acquire the PagingIoResource exclusively at this time ++ // to conform with the resource acquisition described in the set ++ // file information routine. Once again though, you will probably ++ // not need to do this. ++ DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCBPaging Exclusively [FastIo]", 0); ++ DebugTraceState( "FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); ++ ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), TRUE); ++ ++ DebugTrace(DEBUG_TRACE_MISC,"*** FCBPaging acquired [FastIo]", 0); ++ ++ return; ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoRelCreateSec() ++* ++* Description: ++* Not really a fast-io operation. Used by the VMM to release FSD resources ++* after processing a file map (create section object) request. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: None ++* ++*************************************************************************/ ++void Ext2FastIoRelCreateSec( ++IN PFILE_OBJECT FileObject) ++{ ++ ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ ++ // Obtain a pointer to the FCB and CCB for the file stream. ++ PtrCCB = (PtrExt2CCB)(FileObject->FsContext2); ++ ASSERT(PtrCCB); ++ PtrFCB = PtrCCB->PtrFCB; ++ ASSERT(PtrFCB); ++ AssertFCB( PtrFCB ); ++ ++/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) ++ { ++ // Ext2BreakPoint(); ++ DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); ++ return; ++ }*/ ++ ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoRelCreateSec", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ // Release the PagingIoResource for the file stream ++ Ext2ReleaseResource(&(PtrReqdFCB->PagingIoResource)); ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Released in [FastIo]", 0); ++ DebugTraceState( "FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", ++ PtrReqdFCB->PagingIoResource.ActiveCount, ++ PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, ++ PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); ++ ++ // Release the MainResource for the file stream ++ Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); ++ DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", ++ PtrReqdFCB->MainResource.ActiveCount, ++ PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, ++ PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ++ ++ return; ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2AcqLazyWrite() ++* ++* Description: ++* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD ++* resources before performing a delayed write (write behind/lazy write) ++* operation. ++* NOTE: this function really must succeed since the Cache Manager will ++* typically ignore failure and continue on ... ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well) ++* ++*************************************************************************/ ++BOOLEAN Ext2AcqLazyWrite( ++IN PVOID Context, ++IN BOOLEAN Wait) ++{ ++ BOOLEAN ReturnedStatus = TRUE; ++ ++ PtrExt2VCB PtrVCB = NULL; ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ ++ // The context is whatever we passed to the Cache Manager when invoking ++ // the CcInitializeCacheMaps() function. In the case of the sample FSD ++ // implementation, this context is a pointer to the CCB structure. ++ ++ ASSERT(Context); ++ PtrCCB = (PtrExt2CCB)(Context); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2AcqLazyWrite", 0); ++ ++ if(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB) ++ { ++ // ++ // Acquiring Resource for a file write... ++ // ++ PtrFCB = PtrCCB->PtrFCB; ++ AssertFCB( PtrFCB ); ++ } ++ else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) ++ { ++ // ++ // Acquiring Resource for a volume write... ++ // ++ PtrVCB = ( PtrExt2VCB )PtrCCB; ++ PtrCCB = NULL; ++ DebugTrace(DEBUG_TRACE_MISC,"~~~[FastIO call]~~~ Ext2AcqLazyWrite - for Volume", 0); ++ ++ // Acquire nothing... ++ // Just proceed... ++ return TRUE; ++ ++ } ++ else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) ++ { ++ // ++ // This must have been a FCB created / maintained on the FSD's initiative... ++ // This would have been done to cache access to a directory... ++ // ++ PtrFCB = ( PtrExt2FCB )PtrCCB; ++ PtrCCB = NULL; ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Ext2AcqLazyWrite - Invalid context", 0); ++ Ext2BreakPoint(); ++ return FALSE; ++ } ++ ++ if( PtrCCB && PtrCCB->PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); ++ } ++ ++ AssertFCB( PtrFCB ); ++ ++ ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ ++ ++ // Acquire the MainResource in the FCB exclusively. Then, set the ++ // lazy-writer thread id in the FCB structure for identification when ++ // an actual write request is received by the FSD. ++ // Note: The lazy-writer typically always supplies WAIT set to TRUE. ++ ++ DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCB Exclusively [FastIo]", 0); ++ ++ DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ++ if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), ++ Wait)) ++ { ++ DebugTrace(DEBUG_TRACE_MISC,"*** Attempt to acquire FCB FAILED [FastIo]", 0); ++ ReturnedStatus = FALSE; ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); ++ // Now, set the lazy-writer thread id. ++ ASSERT(!(PtrFCB->LazyWriterThreadID)); ++ PtrFCB->LazyWriterThreadID = (unsigned int)(PsGetCurrentThread()); ++ } ++ ++ // If your FSD needs to perform some special preparations in anticipation ++ // of receving a lazy-writer request, do so now. ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2RelLazyWrite() ++* ++* Description: ++* Not really a fast-io operation. Used by the NT Cache Mgr to release FSD ++* resources after performing a delayed write (write behind/lazy write) ++* operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: None ++* ++*************************************************************************/ ++void Ext2RelLazyWrite( ++IN PVOID Context) ++{ ++ ++ BOOLEAN ReturnedStatus = TRUE; ++ ++ PtrExt2VCB PtrVCB = NULL; ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ ++ // The context is whatever we passed to the Cache Manager when invoking ++ // the CcInitializeCacheMaps() function. In the case of the sample FSD ++ // implementation, this context is a pointer to the CCB structure. ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2RelLazyWrite", 0); ++ ++ ASSERT(Context); ++ PtrCCB = (PtrExt2CCB)(Context); ++ ++ if(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB) ++ { ++ PtrFCB = PtrCCB->PtrFCB; ++ AssertFCB( PtrFCB ); ++ } ++ else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) ++ { ++ PtrVCB = ( PtrExt2VCB )PtrCCB; ++ PtrCCB = NULL; ++ DebugTrace(DEBUG_TRACE_MISC,"~~~[FastIO call]~~~ Ext2RelLazyWrite - for Volume", 0); ++ ++ // Acquire was acquired nothing... ++ // Just return... ++ return; ++ ++ } ++ else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) ++ { ++ // ++ // This must have been a FCB created / maintained on the FSD's initiative... ++ // This would have been done to cache access to a directory... ++ // ++ PtrFCB = ( PtrExt2FCB )PtrCCB; ++ PtrCCB = NULL; ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Ext2RelLazyWrite - Invalid context", 0); ++ Ext2BreakPoint(); ++ return ; ++ } ++ ++ if( PtrCCB && PtrCCB->PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); ++ } ++ ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ ++ // Remove the current thread-id from the FCB and release the MainResource. ++ ASSERT( (PtrFCB->LazyWriterThreadID) == (unsigned int)PsGetCurrentThread() ); ++ PtrFCB->LazyWriterThreadID = 0; ++ ++ ++ // Release the acquired resource. ++ Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); ++ DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", ++ PtrReqdFCB->MainResource.ActiveCount, ++ PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, ++ PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ++ ++ // ++ // Undo whatever else seems appropriate at this time... ++ // ++ ++ return; ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2AcqReadAhead() ++* ++* Description: ++* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD ++* resources before performing a read-ahead operation. ++* NOTE: this function really must succeed since the Cache Manager will ++* typically ignore failure and continue on ... ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well) ++* ++*************************************************************************/ ++BOOLEAN Ext2AcqReadAhead( ++IN PVOID Context, ++IN BOOLEAN Wait) ++{ ++ ++ BOOLEAN ReturnedStatus = TRUE; ++ ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ ++ // The context is whatever we passed to the Cache Manager when invoking ++ // the CcInitializeCacheMaps() function. In the case of the sample FSD ++ // implementation, this context is a pointer to the CCB structure. ++ ++ ASSERT(Context); ++ PtrCCB = (PtrExt2CCB)(Context); ++ ASSERT(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2AcqReadAhead", 0); ++ if( PtrCCB && PtrCCB->PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); ++ } ++ ++ PtrFCB = PtrCCB->PtrFCB; ++ ASSERT(PtrFCB); ++ ++ AssertFCB( PtrFCB ); ++/* ++ if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) ++ { ++ // Ext2BreakPoint(); ++ DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); ++ return TRUE; ++ } */ ++ ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ ++ // Acquire the MainResource in the FCB shared. ++ // Note: The read-ahead thread typically always supplies WAIT set to TRUE. ++ DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCB Shared [FastIo]", 0); ++ ++ DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ++ if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), Wait)) ++ { ++ DebugTrace(DEBUG_TRACE_MISC,"*** Attempt to acquire FCB FAILED [FastIo]", 0); ++ ReturnedStatus = FALSE; ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0); ++ } ++ ++ // If your FSD needs to perform some special preparations in anticipation ++ // of receving a read-ahead request, do so now. ++ ++ return ReturnedStatus; ++ ++} ++ ++ ++ ++/************************************************************************* ++* ++* Function: Ext2RelReadAhead() ++* ++* Description: ++* Not really a fast-io operation. Used by the NT Cache Mgr to release FSD ++* resources after performing a read-ahead operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: None ++* ++*************************************************************************/ ++void Ext2RelReadAhead( ++IN PVOID Context) ++{ ++ BOOLEAN ReturnedStatus = TRUE; ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ ++ ++ // The context is whatever we passed to the Cache Manager when invoking ++ // the CcInitializeCacheMaps() function. In the case of the sample FSD ++ // implementation, this context is a pointer to the CCB structure. ++ ++ ASSERT(Context); ++ PtrCCB = (PtrExt2CCB)(Context); ++ ASSERT(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); ++ ++ PtrFCB = PtrCCB->PtrFCB; ++ ++ AssertFCB( PtrFCB ); ++ ++ // ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2RelReadAhead", 0); ++ if( PtrCCB && PtrCCB->PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject ); ++ } ++ ++/* if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) ++ { ++ // Ext2BreakPoint(); ++ DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~ Invalid FCB...", 0); ++ return; ++ } */ ++ ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ ++ ++ // Release the acquired resource. ++ Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0); ++ DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FastIo]", ++ PtrReqdFCB->MainResource.ActiveCount, ++ PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, ++ PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ++ ++ // Of course, your FSD should undo whatever else seems appropriate at this ++ // time. ++ ++ return; ++} ++ ++ ++/* the remaining are only valid under NT Version 4.0 and later */ ++#if(_WIN32_WINNT >= 0x0400) ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoQueryNetInfo() ++* ++* Description: ++* Get information requested by a redirector across the network. This call ++* will originate from the LAN Manager server. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoQueryNetInfo( ++IN PFILE_OBJECT FileObject, ++IN BOOLEAN Wait, ++OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoQueryNetInfo", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoMdlRead() ++* ++* Description: ++* Bypass the traditional IRP method to perform a MDL read operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoMdlRead( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN ULONG LockKey, ++OUT PMDL *MdlChain, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlRead", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoMdlReadComplete() ++* ++* Description: ++* Bypass the traditional IRP method to inform the NT Cache Manager and the ++* FSD that the caller no longer requires the data locked in the system cache ++* or the MDL to stay around anymore .. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoMdlReadComplete( ++IN PFILE_OBJECT FileObject, ++OUT PMDL MdlChain, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlReadComplete", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoPrepareMdlWrite() ++* ++* Description: ++* Bypass the traditional IRP method to prepare for a MDL write operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoPrepareMdlWrite( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++IN ULONG Length, ++IN ULONG LockKey, ++OUT PMDL *MdlChain, ++OUT PIO_STATUS_BLOCK IoStatus, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoPrepareMdlWrite", 0); ++ if( FileObject ) ++ { ++ DebugTrace( DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoMdlWriteComplete() ++* ++* Description: ++* Bypass the traditional IRP method to inform the NT Cache Manager and the ++* FSD that the caller has updated the contents of the MDL. This data can ++* now be asynchronously written out to secondary storage by the Cache Mgr. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: TRUE/FALSE ++* ++*************************************************************************/ ++BOOLEAN Ext2FastIoMdlWriteComplete( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER FileOffset, ++OUT PMDL MdlChain, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ BOOLEAN ReturnedStatus = FALSE; // fast i/o failed/not allowed ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoMdlWriteComplete", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ ++ try ++ { ++ ++ // See description in Ext2FastIoRead() before filling-in the ++ // stub here. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(ReturnedStatus); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoAcqModWrite() ++* ++* Description: ++* Not really a fast-io operation. Used by the VMM to acquire FSD resources ++* before initiating a write operation via the Modified Page/Block Writer. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error (try not to return an error, will 'ya ? :-) ++* ++*************************************************************************/ ++NTSTATUS Ext2FastIoAcqModWrite( ++IN PFILE_OBJECT FileObject, ++IN PLARGE_INTEGER EndingOffset, ++OUT PERESOURCE *ResourceToRelease, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~ Ext2FastIoAcqModWrite", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ try ++ { ++ ++ // You must determine which resource(s) you would like to ++ // acquire at this time. You know that a write is imminent; ++ // you will probably therefore acquire appropriate resources ++ // exclusively. ++ ++ // You must first get the FCB and CCB pointers from the file object ++ // that is passed in to this function (as an argument). Note that ++ // the ending offset (when examined in conjunction with current valid data ++ // length) may help you in determining the appropriate resource(s) to acquire. ++ ++ // For example, if the ending offset is beyond current valid data length, ++ // you may decide to acquire *both* the MainResource and the PagingIoResource ++ // exclusively; otherwise, you may decide simply to acquire the PagingIoResource. ++ ++ // Consult the text for more information on synchronization in FSDs. ++ ++ // One final note; the VMM expects that you will return a pointer to ++ // the resource that you acquired (single return value). This pointer ++ // will be returned back to you in the release call (below). ++ ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoRelModWrite() ++* ++* Description: ++* Not really a fast-io operation. Used by the VMM to release FSD resources ++* after processing a modified page/block write operation. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error (an error returned here is really not expected!) ++* ++*************************************************************************/ ++NTSTATUS Ext2FastIoRelModWrite( ++IN PFILE_OBJECT FileObject, ++IN PERESOURCE ResourceToRelease, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace( DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRelModWrite", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ try ++ { ++ ++ // The MPW has complete the write for modified pages and therefore ++ // wants you to release pre-acquired resource(s). ++ ++ // You must undo here whatever it is that you did in the ++ // Ext2FastIoAcqModWrite() call above. ++ ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoAcqCcFlush() ++* ++* Description: ++* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD ++* resources before performing a CcFlush() operation on a specific file ++* stream. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2FastIoAcqCcFlush( ++IN PFILE_OBJECT FileObject, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoAcqCcFlush", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ try ++ { ++ // Acquire appropriate resources that will allow correct synchronization ++ // with a flush call (and avoid deadlock). ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FastIoRelCcFlush() ++* ++* Description: ++* Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD ++* resources before performing a CcFlush() operation on a specific file ++* stream. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2FastIoRelCcFlush( ++IN PFILE_OBJECT FileObject, ++IN PDEVICE_OBJECT DeviceObject) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ ++ FsRtlEnterFileSystem(); ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "~~~[FastIO call]~~~ Ext2FastIoRelCcFlush", 0); ++ if( FileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject); ++ } ++ ++ try ++ { ++ try ++ { ++ // Release resources acquired in Ext2FastIoAcqCcFlush() above. ++ NOTHING; ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, NULL); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++#endif //_WIN32_WINNT >= 0x0400 diff --cc reactos/drivers/filesystems/ext2/src/fileinfo.c index 00000000000,0047d50f23f..0047d50f23f mode 000000,100644..100644 --- a/reactos/drivers/filesystems/ext2/src/fileinfo.c +++ b/reactos/drivers/filesystems/ext2/src/fileinfo.c diff --cc reactos/drivers/filesystems/ext2/src/flush.c index 00000000000,fd25fa33899..fd25fa33899 mode 000000,100644..100644 --- a/reactos/drivers/filesystems/ext2/src/flush.c +++ b/reactos/drivers/filesystems/ext2/src/flush.c diff --cc reactos/drivers/filesystems/ext2/src/fsctrl.c index 00000000000,00000000000..b25eed32ff6 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/fsctrl.c @@@ -1,0 -1,0 +1,944 @@@ ++/************************************************************************* ++* ++* File: fsctrl.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains code to handle the various File System Control calls. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++ ++ ++#include "ext2fsd.h" ++ ++ ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_FILE_CONTROL ++#define DEBUG_LEVEL (DEBUG_TRACE_FSCTRL) ++ ++ ++NTSTATUS ++Ext2MountVolume( ++ IN PIRP Irp, ++ IN PIO_STACK_LOCATION IrpSp ); ++ ++NTSTATUS ++Ext2GetPartitionInfo( ++ IN PDEVICE_OBJECT TargetDeviceObject, ++ IN PPARTITION_INFORMATION PartitionInformation ++ ); ++ ++NTSTATUS ++Ext2GetDriveLayout( ++ IN PDEVICE_OBJECT TargetDeviceObject, ++ IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation, ++ IN int BufferSize ++ ); ++ ++BOOLEAN ++Ext2PerformVerifyDiskRead( ++ IN PDEVICE_OBJECT TargetDeviceObject, ++ IN PVOID Buffer, ++ IN LONGLONG Lbo, ++ IN ULONG NumberOfBytesToRead ++ ); ++ ++NTSTATUS Ext2UserFileSystemRequest( ++ IN PIRP Irp, ++ IN PIO_STACK_LOCATION IrpSp ); ++ ++ ++/************************************************************************* ++* ++* Function: Ext2FileSystemControl ++* ++* Description: ++* The I/O Manager will invoke this routine to handle a ++* File System Control IRP ++* ++* Expected Interrupt Level (for execution) : ++* ++* ??? ++* ++* Arguments: ++* ++* DeviceObject - Supplies the volume device object where the ++* file exists ++* ++* Irp - Supplies the Irp being processed ++* ++* ++* Return Value: ++* ++* NTSTATUS - The FSD status for the IRP ++* ++*************************************************************************/ ++NTSTATUS ++Ext2FileSystemControl( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp ++ ) ++{ ++ ++ NTSTATUS Status = STATUS_SUCCESS; ++ PIO_STACK_LOCATION IrpSp; ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "File System Control IRP Received...", 0); ++ ++ // Ext2BreakPoint(); ++ ++ FsRtlEnterFileSystem(); ++ ++ ASSERT(DeviceObject); ++ ASSERT(Irp); ++ ++ // ++ // Get a pointer to the current Irp stack location ++ // ++ IrpSp = IoGetCurrentIrpStackLocation( Irp ); ++ ++ ++ if( IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) ++ { ++ DebugTrace(DEBUG_TRACE_MOUNT, "Mount Request Received...", 0); ++ Status = Ext2MountVolume ( Irp, IrpSp ); ++ Ext2CompleteRequest( Irp, Status ); ++ } ++ else if( IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST ) ++ { ++ DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_USER_FS_REQUEST received...", 0); ++ Status = Ext2UserFileSystemRequest( Irp, IrpSp ); ++ Ext2CompleteRequest( Irp, Status ); ++ } ++ else ++ { ++ if( IrpSp->MinorFunction == IRP_MN_VERIFY_VOLUME ) ++ { ++ DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_VERIFY_VOLUME received...", 0); ++ } ++ else if( IrpSp->MinorFunction == IRP_MN_LOAD_FILE_SYSTEM ) ++ { ++ DebugTrace(DEBUG_TRACE_FSCTRL, "IRP_MN_LOAD_FILE_SYSTEM received...", 0); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_FSCTRL, "Unknown Minor IRP code received...", 0); ++ } ++ ++ Status = STATUS_INVALID_DEVICE_REQUEST; ++ Ext2CompleteRequest( Irp, Status ); ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return Status; ++} ++ ++ ++ ++/************************************************************************* ++* ++* Function: Ext2MountVolume() ++* ++* Description: ++* This routine verifies and mounts the volume; ++* Called by FSCTRL IRP handler to attempt a ++* volume mount. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* ++* Arguments: ++* ++* Irp - Supplies the Irp being processed ++* IrpSp - Irp Stack Location pointer ++* ++* Return Value: ++* ++* NTSTATUS - The Mount status ++* ++*************************************************************************/ ++NTSTATUS ++Ext2MountVolume ( ++ IN PIRP Irp, ++ IN PIO_STACK_LOCATION IrpSp ) ++{ ++ ++ // Volume Parameter Block ++ PVPB PtrVPB; ++ ++ // The target device object ++ PDEVICE_OBJECT TargetDeviceObject = NULL; ++ ++ // The new volume device object (to be created if partition is Ext2) ++ PDEVICE_OBJECT PtrVolumeDeviceObject = NULL; ++ ++ // Return Status ++ NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME; ++ ++ // Number of bytes to read for Volume verification... ++ unsigned long NumberOfBytesToRead = 0; ++ ++ // Starting Offset for 'read' ++ LONGLONG StartingOffset = 0; ++ ++ // Boot Sector information... ++ PPACKED_BOOT_SECTOR BootSector = NULL; ++ ++ // Ext2 Super Block information... ++ PEXT2_SUPER_BLOCK SuperBlock = NULL; ++ ++ // Volume Control Block ++ PtrExt2VCB PtrVCB = NULL; ++ ++ // The File Object for the root directory ++ PFILE_OBJECT PtrRootFileObject = NULL; ++ ++ // Flag ++ int WeClearedVerifyRequiredBit; ++ ++ // Used by a for loop... ++ unsigned int i; ++ ++ // ++ LARGE_INTEGER VolumeByteOffset; ++ ++ unsigned long LogicalBlockSize = 0; ++ ++ // Buffer Control Block ++ PBCB PtrBCB = NULL; ++ ++ // Cache Buffer - used for pinned access of volume... ++ PVOID PtrCacheBuffer = NULL; ++ ++ PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; ++ ++ PEXT2_INODE PtrInode = NULL; ++ ++ // Inititalising variables ++ ++ PtrVPB = IrpSp->Parameters.MountVolume.Vpb; ++ TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject; ++ ++ try ++ { ++ // ++ // 1. Reading in Volume meta data ++ // ++ ++ // Temporarily clear the DO_VERIFY_VOLUME Flag ++ WeClearedVerifyRequiredBit = 0; ++ if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) ++ { ++ Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ); ++ WeClearedVerifyRequiredBit = 1; ++ } ++ ++ // Allocating memory for reading in Boot Sector... ++ NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), TargetDeviceObject->SectorSize ); ++ BootSector = Ext2AllocatePool( PagedPool, NumberOfBytesToRead ); ++ RtlZeroMemory( BootSector, NumberOfBytesToRead ); ++ ++ // Reading in Boot Sector ++ StartingOffset = 0L; ++ Ext2PerformVerifyDiskRead ( TargetDeviceObject, ++ BootSector, StartingOffset, NumberOfBytesToRead ); ++ ++ // Allocating memory for reading in Super Block... ++ ++ SuperBlock = Ext2AllocatePool( PagedPool, NumberOfBytesToRead ); ++ RtlZeroMemory( SuperBlock, NumberOfBytesToRead ); ++ StartingOffset = 1024; ++ ++ // Reading in the Super Block... ++ Ext2PerformVerifyDiskRead ( TargetDeviceObject, ++ SuperBlock, StartingOffset, NumberOfBytesToRead ); ++ ++ // Resetting the DO_VERIFY_VOLUME Flag ++ if( WeClearedVerifyRequiredBit ) ++ { ++ PtrVPB->RealDevice->Flags |= DO_VERIFY_VOLUME; ++ } ++ ++ // Verifying the Super Block.. ++ if( SuperBlock->s_magic == EXT2_SUPER_MAGIC ) ++ { ++ // ++ // Found a valid super block. ++ // No more tests for now. ++ // Assuming that this is an ext2 partition... ++ // Going ahead with mount. ++ // ++ DebugTrace(DEBUG_TRACE_MOUNT, "Valid Ext2 partition detected\nMounting %s...", SuperBlock->s_volume_name); ++ // ++ // 2. Creating a volume device object ++ // ++ if (!NT_SUCCESS( IoCreateDevice( ++ Ext2GlobalData.Ext2DriverObject, // (This) Driver object ++ Ext2QuadAlign( sizeof(Ext2VCB) ), // Device Extension ++ NULL, // Device Name - no name ;) ++ FILE_DEVICE_DISK_FILE_SYSTEM, // Disk File System ++ 0, // DeviceCharacteristics ++ FALSE, // Not an exclusive device ++ (PDEVICE_OBJECT *)&PtrVolumeDeviceObject)) // The Volume Device Object ++ ) ++ { ++ try_return( Status ); ++ } ++ ++ // ++ // Our alignment requirement is the larger of the processor alignment requirement ++ // already in the volume device object and that in the TargetDeviceObject ++ // ++ ++ if (TargetDeviceObject->AlignmentRequirement > PtrVolumeDeviceObject->AlignmentRequirement) ++ { ++ PtrVolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; ++ } ++ ++ // ++ // Clearing the Device Initialising Flag ++ // ++ Ext2ClearFlag( PtrVolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); ++ ++ ++ // ++ // Setting the Stack Size for the newly created Volume Device Object ++ // ++ PtrVolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); ++ ++ ++ // ++ // 3. Creating the link between Target Device Object ++ // and the Volume Device Object via the Volume Parameter Block ++ // ++ PtrVPB->DeviceObject = PtrVolumeDeviceObject; ++ ++ // Remembring the Volume parameters in the VPB bock ++ for( i = 0; i < 16 ; i++ ) ++ { ++ PtrVPB->VolumeLabel[i] = SuperBlock->s_volume_name[i]; ++ if( SuperBlock->s_volume_name[i] == 0 ) ++ break; ++ } ++ PtrVPB->VolumeLabelLength = i * 2; ++ PtrVPB->SerialNumber = ((ULONG*)SuperBlock->s_uuid)[0]; ++ ++ // ++ // 4. Initialise the Volume Comtrol Block ++ // ++ { ++ LARGE_INTEGER AllocationSize; ++ ++ AllocationSize .QuadPart = ++ ( EXT2_MIN_BLOCK_SIZE << SuperBlock->s_log_block_size ) * ++ SuperBlock->s_blocks_count; ++ ++ Ext2InitializeVCB( ++ PtrVolumeDeviceObject, ++ TargetDeviceObject, ++ PtrVPB, ++ &AllocationSize); ++ PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); ++ ASSERT( PtrVCB ); ++ } ++ ++ PtrVCB->InodesCount = SuperBlock->s_inodes_count; ++ PtrVCB->BlocksCount = SuperBlock->s_blocks_count; ++ PtrVCB->ReservedBlocksCount = SuperBlock->s_r_blocks_count; ++ PtrVCB->FreeBlocksCount = SuperBlock->s_free_blocks_count; ++ PtrVCB->FreeInodesCount = SuperBlock->s_free_inodes_count; ++ PtrVCB->LogBlockSize = SuperBlock->s_log_block_size; ++ PtrVCB->InodesPerGroup = SuperBlock->s_inodes_per_group; ++ PtrVCB->BlocksPerGroup = SuperBlock->s_blocks_per_group; ++ PtrVCB->NoOfGroups = ( SuperBlock->s_blocks_count - SuperBlock->s_first_data_block ++ + SuperBlock->s_blocks_per_group - 1 ) ++ / SuperBlock->s_blocks_per_group; ++ ++ PtrVCB->PtrGroupDescriptors = Ext2AllocatePool( NonPagedPool, sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups ); ++ ++ RtlZeroMemory( PtrVCB->PtrGroupDescriptors , sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups ); ++ ++ // ++ // Attempting to Read in some matadata from the Cache... ++ // using pin access... ++ // ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ // ++ // Reading Group Descriptors... ++ // ++ if( PtrVCB->LogBlockSize ) ++ { ++ // First block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize; ++ } ++ else ++ { ++ // Second block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize * 2; ++ } ++ ++ NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); ++ NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); ++ ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrBCB, ++ &PtrCacheBuffer )) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); ++ } ++ else ++ { ++ // ++ // Saving up Often Used Group Descriptor Information in the VCB... ++ // ++ unsigned int DescIndex ; ++ ++ DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); ++ PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer; ++ for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ ) ++ { ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock ++ = PtrGroupDescriptor[ DescIndex ].bg_inode_table; ++ ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock ++ = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap ++ ; ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock ++ = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap ++ ; ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount ++ = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count; ++ ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount ++ = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count; ++ } ++ CcUnpinData( PtrBCB ); ++ PtrBCB = NULL; ++ } ++ ++ // ++ // 5. Creating a Root Directory FCB ++ // ++ PtrRootFileObject = IoCreateStreamFileObject(NULL, TargetDeviceObject ); ++ if( !PtrRootFileObject ) ++ { ++ try_return( Status ); ++ } ++ // ++ // Associate the file stream with the Volume parameter block... ++ // I do it now ++ // ++ PtrRootFileObject->Vpb = PtrVCB->PtrVPB; ++ ++ PtrRootFileObject->ReadAccess = TRUE; ++ PtrRootFileObject->WriteAccess = TRUE; ++ ++ { ++ PtrExt2ObjectName PtrObjectName; ++ LARGE_INTEGER ZeroSize; ++ ++ PtrObjectName = Ext2AllocateObjectName(); ++ RtlInitUnicodeString( &PtrObjectName->ObjectName, L"\\" ); ++ Ext2CopyWideCharToUnicodeString( &PtrObjectName->ObjectName, L"\\" ); ++ ++ ++ ZeroSize.QuadPart = 0; ++ if ( !NT_SUCCESS( Ext2CreateNewFCB( ++ &PtrVCB->PtrRootDirectoryFCB, // Root FCB ++ ZeroSize, // AllocationSize, ++ ZeroSize, // EndOfFile, ++ PtrRootFileObject, // The Root Dircetory File Object ++ PtrVCB, ++ PtrObjectName ) ) ) ++ { ++ try_return( Status ); ++ } ++ ++ ++ PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY | EXT2_FCB_ROOT_DIRECTORY; ++ ++ ++ } ++ ++ PtrVCB->PtrRootDirectoryFCB->DcbFcb.Dcb.PtrDirFileObject = PtrRootFileObject; ++ PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO; ++ PtrRootFileObject->SectionObjectPointer = &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject); ++ RtlInitUnicodeString( &PtrRootFileObject->FileName, L"\\" ); ++ ++ Ext2InitializeFCBInodeInfo( PtrVCB->PtrRootDirectoryFCB ); ++ ++ // ++ // Initiating caching for root directory... ++ // ++ ++ CcInitializeCacheMap(PtrRootFileObject, ++ (PCC_FILE_SIZES)(&(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), ++ TRUE, // We will utilize pin access for directories ++ &(Ext2GlobalData.CacheMgrCallBacks), // callbacks ++ PtrVCB->PtrRootDirectoryFCB ); // The context used in callbacks ++ ++ ++ // ++ // 6. Update the VCB Flags ++ // ++ PtrVCB->VCBFlags |= EXT2_VCB_FLAGS_VOLUME_MOUNTED ; // | EXT2_VCB_FLAGS_VOLUME_READ_ONLY; ++ ++ ++ // ++ // 7. Mount Success ++ // ++ Status = STATUS_SUCCESS; ++ ++ { ++ // ++ // This block is for testing.... ++ // To be removed... ++ ++ /* ++ EXT2_INODE Inode ; ++ Ext2ReadInode( PtrVCB, 100, &Inode ); ++ DebugTrace( DEBUG_TRACE_MISC, "Inode size= %lX [FS Ctrl]", Inode.i_size ); ++ Ext2DeallocInode( NULL, PtrVCB, 0xfb6 ); ++ */ ++ } ++ ++ // ObDereferenceObject( TargetDeviceObject ); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MOUNT, "Failing mount. Partition not Ext2...", 0); ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ // Freeing Allocated Memory... ++ if( SuperBlock != NULL ) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", SuperBlock ); ++ ExFreePool( SuperBlock ); ++ } ++ if( BootSector != NULL ) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", BootSector); ++ ExFreePool( BootSector ); ++ } ++ ++ // start unwinding if we were unsuccessful ++ if (!NT_SUCCESS( Status )) ++ { ++ ++ } ++ } ++ ++ return Status; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2MountVolume() ++* ++* Description: ++* This routine is used for querying the partition information. ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Arguments: ++* ++* TargetDeviceObject - The target of the query ++* PartitionInformation - Receives the result of the query ++* ++* Return Value: ++* ++* NTSTATUS - The return status for the operation ++* ++*************************************************************************/ ++NTSTATUS ++Ext2GetPartitionInfo ( ++ IN PDEVICE_OBJECT TargetDeviceObject, ++ IN PPARTITION_INFORMATION PartitionInformation ++ ) ++{ ++ PIRP Irp; ++ KEVENT *PtrEvent = NULL; ++ NTSTATUS Status; ++ IO_STATUS_BLOCK Iosb; ++ ++ // ++ // Query the partition table ++ // ++ PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) ) ); ++ ++ ++ ++ ++ KeInitializeEvent( PtrEvent, NotificationEvent, FALSE ); ++ ++ Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO, ++ TargetDeviceObject, ++ NULL, ++ 0, ++ PartitionInformation, ++ sizeof(PARTITION_INFORMATION), ++ FALSE, ++ PtrEvent, ++ &Iosb ); ++ ++ if ( Irp == NULL ) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); ++ ExFreePool( PtrEvent ); ++ return 0; ++ } ++ ++ Status = IoCallDriver( TargetDeviceObject, Irp ); ++ ++ if ( Status == STATUS_PENDING ) { ++ ++ (VOID) KeWaitForSingleObject( PtrEvent, ++ Executive, ++ KernelMode, ++ FALSE, ++ (PLARGE_INTEGER)NULL ); ++ ++ Status = Iosb.Status; ++ } ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); ++ ExFreePool( PtrEvent ); ++ return Status; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2MountVolume() ++* ++* Description: ++* This routine is used for querying the Drive Layout Information. ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Arguments: ++* ++* TargetDeviceObject - The target of the query ++* PartitionInformation - Receives the result of the query ++* ++* Return Value: ++* ++* NTSTATUS - The return status for the operation ++* ++*************************************************************************/ ++NTSTATUS Ext2GetDriveLayout ( ++ IN PDEVICE_OBJECT TargetDeviceObject, ++ IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation, ++ IN int BufferSize ++ ) ++{ ++ PIRP Irp; ++ KEVENT *PtrEvent = NULL; ++ NTSTATUS Status; ++ IO_STATUS_BLOCK Iosb; ++ ++ // ++ // Query the partition table ++ // ++ PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) ) ); ++ KeInitializeEvent( PtrEvent, NotificationEvent, FALSE ); ++ Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_LAYOUT, ++ TargetDeviceObject, ++ NULL, ++ 0, ++ DriveLayoutInformation, ++ BufferSize, ++ FALSE, ++ PtrEvent, ++ &Iosb ); ++ ++ if ( Irp == NULL ) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); ++ ExFreePool( PtrEvent ); ++ return 0; ++ } ++ ++ Status = IoCallDriver( TargetDeviceObject, Irp ); ++ ++ if ( Status == STATUS_PENDING ) { ++ ++ (VOID) KeWaitForSingleObject( PtrEvent, ++ Executive, ++ KernelMode, ++ FALSE, ++ (PLARGE_INTEGER)NULL ); ++ ++ Status = Iosb.Status; ++ } ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", PtrEvent); ++ ExFreePool( PtrEvent ); ++ return Status; ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2MountVolume() ++* ++* Description: ++* This routine is used for performing a verify read... ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Arguments: ++* TargetDeviceObject - The target of the query ++* PartitionInformation - Receives the result of the query ++* ++* Return Value: ++* NTSTATUS - The return status for the operation ++* ++*************************************************************************/ ++BOOLEAN Ext2PerformVerifyDiskRead( ++ IN PDEVICE_OBJECT TargetDeviceObject, ++ IN PVOID Buffer, ++ IN LONGLONG Lbo, ++ IN ULONG NumberOfBytesToRead ) ++{ ++ KEVENT Event; ++ PIRP Irp; ++ LARGE_INTEGER ByteOffset; ++ NTSTATUS Status; ++ IO_STATUS_BLOCK Iosb; ++ ++ // ++ // Initialize the event we're going to use ++ // ++ KeInitializeEvent( &Event, NotificationEvent, FALSE ); ++ ++ // ++ // Build the irp for the operation ++ // ++ ByteOffset.QuadPart = Lbo; ++ Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ, ++ TargetDeviceObject, ++ Buffer, ++ NumberOfBytesToRead, ++ &ByteOffset, ++ &Event, ++ &Iosb ); ++ ++ if ( Irp == NULL ) ++ { ++ Status = FALSE; ++ } ++ ++ Ext2SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME ); ++ ++ // ++ // Call the device to do the read and wait for it to finish. ++ // ++ Status = IoCallDriver( TargetDeviceObject, Irp ); ++ if (Status == STATUS_PENDING) ++ { ++ (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); ++ Status = Iosb.Status; ++ } ++ ++ ASSERT(Status != STATUS_VERIFY_REQUIRED); ++ ++ // ++ // Special case this error code because this probably means we used ++ // the wrong sector size and we want to reject STATUS_WRONG_VOLUME. ++ // ++ ++ if (Status == STATUS_INVALID_PARAMETER) ++ { ++ ++ return FALSE; ++ } ++ ++ // ++ // If it doesn't succeed then either return or raise the error. ++ // ++ ++ if (!NT_SUCCESS(Status)) ++ { ++ return FALSE; ++ } ++ ++ // ++ // And return to our caller ++ // ++ return TRUE; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2UserFileSystemRequest() ++* ++* Description: ++* This routine handles User File System Requests ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* ++* Arguments: ++* ++* Irp - Supplies the Irp being processed ++* IrpSp - Irp Stack Location pointer ++* ++* Return Value: NT_STATUS ++* ++*************************************************************************/ ++NTSTATUS Ext2UserFileSystemRequest ( ++ IN PIRP Irp, ++ IN PIO_STACK_LOCATION IrpSp ) ++{ ++ NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; ++ ULONG FsControlCode; ++ ++ IrpSp = IoGetCurrentIrpStackLocation( Irp ); ++ ++ try ++ { ++#ifdef _GNU_NTIFS_ ++ FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.FileSystemControl.FsControlCode; ++#else ++ FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; ++#endif ++ ++ switch ( FsControlCode ) ++ { ++ ++ case FSCTL_REQUEST_OPLOCK_LEVEL_1: ++ DebugTrace(DEBUG_TRACE_FSCTRL, "FSCTL_REQUEST_OPLOCK_LEVEL_1", 0); ++ break; ++ case FSCTL_REQUEST_OPLOCK_LEVEL_2: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL ", 0); ++ break; ++ case FSCTL_REQUEST_BATCH_OPLOCK: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_REQUEST_OPLOCK_LEVEL_2 ", 0); ++ break; ++ case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: ++ DebugTrace(DEBUG_TRACE_MISC, " FSCTL_OPLOCK_BREAK_ACKNOWLEDGE ", 0); ++ break; ++ case FSCTL_OPBATCH_ACK_CLOSE_PENDING: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPBATCH_ACK_CLOSE_PENDING ", 0); ++ break; ++ case FSCTL_OPLOCK_BREAK_NOTIFY: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPLOCK_BREAK_NOTIFY ", 0); ++ break; ++ case FSCTL_OPLOCK_BREAK_ACK_NO_2: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_OPLOCK_BREAK_ACK_NO_2 ", 0); ++ break; ++ case FSCTL_LOCK_VOLUME: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_LOCK_VOLUME ", 0); ++ break; ++ case FSCTL_UNLOCK_VOLUME: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_UNLOCK_VOLUME ", 0); ++ break; ++ case FSCTL_DISMOUNT_VOLUME: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_DISMOUNT_VOLUME ", 0); ++ break; ++ case FSCTL_MARK_VOLUME_DIRTY: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_MARK_VOLUME_DIRTY ", 0); ++ break; ++ case FSCTL_IS_VOLUME_DIRTY: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_VOLUME_DIRTY ", 0); ++ break; ++ case FSCTL_IS_VOLUME_MOUNTED: ++ Status = Ext2VerifyVolume(Irp, IrpSp ); ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_VOLUME_MOUNTED ", 0); ++ break; ++ case FSCTL_IS_PATHNAME_VALID: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_IS_PATHNAME_VALID ", 0); ++ break; ++ case FSCTL_QUERY_RETRIEVAL_POINTERS: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_QUERY_RETRIEVAL_POINTERS ", 0); ++ break; ++ case FSCTL_QUERY_FAT_BPB: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_QUERY_FAT_BPB ", 0); ++ break; ++ case FSCTL_FILESYSTEM_GET_STATISTICS: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_FILESYSTEM_GET_STATISTICS ", 0); ++ break; ++ case FSCTL_GET_VOLUME_BITMAP: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_GET_VOLUME_BITMAP ", 0); ++ break; ++ case FSCTL_GET_RETRIEVAL_POINTERS: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_GET_RETRIEVAL_POINTERS ", 0); ++ break; ++ case FSCTL_MOVE_FILE: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_MOVE_FILE ", 0); ++ break; ++ case FSCTL_ALLOW_EXTENDED_DASD_IO: ++ DebugTrace(DEBUG_TRACE_FSCTRL, " FSCTL_ALLOW_EXTENDED_DASD_IO ", 0); ++ break; ++ default : ++ DebugTrace(DEBUG_TRACE_FSCTRL, "Unknown FSCTRL !!!", 0); ++ ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ ++ } ++ return Status; ++} ++ ++ ++ ++NTSTATUS Ext2VerifyVolume ( ++ IN PIRP Irp, ++ IN PIO_STACK_LOCATION IrpSp ) ++{ ++ ++ PVPB PtrVPB; ++ ++ PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb; ++ if( IrpSp->FileObject ) ++ { ++ PtrVPB = IrpSp->FileObject->Vpb; ++ } ++ if( !PtrVPB ) ++ { ++ PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb; ++ } ++ ++ if( !PtrVPB ) ++ { ++ return STATUS_WRONG_VOLUME; ++ } ++ ++ ++ if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) ++ { ++ // ++ // Not doing a verify! ++ // Just acting as if everyting is fine! ++ // THis should do for now ++ // ++ Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ); ++ ++ } ++ return STATUS_SUCCESS; ++} diff --cc reactos/drivers/filesystems/ext2/src/io.c index 00000000000,00000000000..9991cc1593d new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/io.c @@@ -1,0 -1,0 +1,543 @@@ ++/************************************************************************* ++* ++* File: io.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* This file contains low level disk io routines. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_IO ++ ++/************************************************************************* ++* ++* Function: Ext2PassDownMultiReadWriteIRP() ++* ++* Description: ++* pass down multiple read IRPs as Associated IRPs ++* ++* Expected Interrupt Level (for execution) : ++* ++* ? ++* ++* Return Value: STATUS_SUCCESS / STATUS_PENDING / Error ++* ++*************************************************************************/ ++NTSTATUS Ext2PassDownMultiReadWriteIRP( ++ PEXT2_IO_RUN PtrIoRuns, ++ UINT Count, ++ ULONG TotalReadWriteLength, ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2FCB PtrFCB, ++ BOOLEAN SynchronousIo) ++{ ++ PIRP PtrMasterIrp; ++ PIRP PtrAssociatedIrp; ++ PIO_STACK_LOCATION PtrIrpSp; ++ PMDL PtrMdl; ++ PtrExt2VCB PtrVCB; ++ UINT i; ++ ULONG BufferOffset; ++ PEXT2_IO_CONTEXT PtrIoContext = NULL; ++ PKEVENT PtrSyncEvent = NULL; ++ ULONG LogicalBlockSize; ++ ULONG ReadWriteLength; ++ ++ NTSTATUS RC = STATUS_SUCCESS; ++ ++ PtrVCB = PtrFCB->PtrVCB; ++ PtrMasterIrp = PtrIrpContext->Irp; ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ try ++ { ++ if( !SynchronousIo ) ++ { ++ IoMarkIrpPending( PtrIrpContext->Irp ); ++ // We will be returning STATUS_PENDING... ++ } ++ ++ if( !PtrMasterIrp->MdlAddress ) ++ { ++ Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength ); ++ } ++ ++ if( SynchronousIo ) ++ { ++ PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); ++ if ( !PtrSyncEvent ) ++ { ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return ( RC ); ++ } ++ KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); ++ } ++ // ++ // Allocate and initialize a completion context ++ // ++ PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); ++ if ( !PtrIoContext ) ++ { ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return ( RC ); ++ } ++ ++ RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); ++ PtrIoContext->Count = Count; ++ PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; ++ PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); ++ PtrIoContext->PtrMasterIrp = PtrMasterIrp; ++ PtrIoContext->PtrSyncEvent = PtrSyncEvent; ++ PtrIoContext->ReadWriteLength = TotalReadWriteLength; ++ ++ ++ ++ for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength ) ++ { ++ ++ ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset; ++ ++ // ++ // Allocating an Associated IRP... ++ // ++ PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp, ++ (CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) ); ++ PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp; ++ ASSERT ( PtrAssociatedIrp ); ++ PtrMasterIrp->AssociatedIrp.IrpCount ++; ++ ++ // ++ // Allocating a Memory Descriptor List... ++ // ++ PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, // Virtual Address ++ ReadWriteLength, FALSE, FALSE, PtrAssociatedIrp ); ++ ++ // ++ // and building a partial MDL... ++ // ++ IoBuildPartialMdl( PtrMasterIrp->MdlAddress, ++ PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength ); ++ ++ // ++ // Create an Irp stack location for ourselves... ++ // ++ IoSetNextIrpStackLocation( PtrAssociatedIrp ); ++ PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp ); ++ ++ // ++ // Setup the Stack location to describe our read. ++ // ++ PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; ++ if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) ++ { ++ PtrIrpSp->Parameters.Read.Length = ReadWriteLength; ++ PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = ++ PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); ++ } ++ else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) ++ { ++ PtrIrpSp->Parameters.Write.Length = ReadWriteLength; ++ PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = ++ PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); ++ } ++ ++ // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; ++ // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock; ++ ++ ++ // ++ // Setup a completion routine... ++ // ++ IoSetCompletionRoutine( PtrAssociatedIrp, ++ SynchronousIo ? ++ Ext2MultiSyncCompletionRoutine : ++ Ext2MultiAsyncCompletionRoutine, ++ PtrIoContext, TRUE, TRUE, TRUE ); ++ ++ // ++ // Initialise the next stack location for the driver below us to use... ++ // ++ PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp ); ++ PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction; ++ if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) ++ { ++ PtrIrpSp->Parameters.Read.Length = ReadWriteLength; ++ PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); ++ } ++ else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) ++ { ++ PtrIrpSp->Parameters.Write.Length = ReadWriteLength; ++ PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); ++ } ++ ++ // PtrIrpSp->Parameters.Read.Length = ReadWriteLength; ++ // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = ++ // PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize ); ++ } ++ ++ for( i = 0; i < Count; i++ ) { ++ DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i); ++ IoCallDriver( PtrVCB->TargetDeviceObject, PtrIoRuns[ i].PtrAssociatedIrp ); ++ } ++ ++ if( SynchronousIo ) ++ { ++ // ++ // Synchronous IO ++ // Wait for the IO to complete... ++ // ++ DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql()); ++ KeWaitForSingleObject( PtrSyncEvent, ++ Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); ++ DbgPrint("DEADLY WAIT DONE\n"); ++ try_return ( RC ); ++ } ++ else ++ { ++ // Asynchronous IO... ++ RC = STATUS_PENDING; ++ try_return ( RC ); ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrSyncEvent ) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); ++ ExFreePool( PtrSyncEvent ); ++ } ++ if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) ++ { ++ // ++ // This means we are getting out of ++ // this function without doing a read ++ // due to an error, maybe... ++ // ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext); ++ ExFreePool( PtrIoContext ); ++ } ++ } ++ return(RC); ++} ++ ++NTSTATUS Ext2PassDownSingleReadWriteIRP( ++ PtrExt2IrpContext PtrIrpContext, ++ PIRP PtrIrp, ++ PtrExt2VCB PtrVCB, ++ LARGE_INTEGER ByteOffset, ++ uint32 ReadWriteLength, ++ BOOLEAN SynchronousIo) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ ++ PEXT2_IO_CONTEXT PtrIoContext = NULL; ++ PKEVENT PtrSyncEvent = NULL; ++ PVOID PtrReadBuffer = NULL; ++ ULONG ReadBufferLength = 0; ++ ++ ULONG LogicalBlockNo = 0; ++ ULONG LogicalBlockSize = 0; ++ ULONG PhysicalBlockSize = 0; ++ ++ uint32 NumberBytesRead = 0; ++ int i; ++ PIO_STACK_LOCATION PtrIrpNextSp = NULL; ++ ++ try ++ { ++ if( !PtrIrp->MdlAddress ) ++ { ++ Ext2LockCallersBuffer( PtrIrp, TRUE, ReadWriteLength ); ++ } ++ ++ ++ if( SynchronousIo ) ++ { ++ PtrSyncEvent = Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) ); ++ if ( !PtrSyncEvent ) ++ { ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return ( RC ); ++ } ++ KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE ); ++ } ++ ++ // ++ // Allocate and initialize a completion context ++ // ++ PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) ); ++ if ( !PtrIoContext ) ++ { ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return ( RC ); ++ } ++ ++ RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) ); ++ PtrIoContext->Count = 1; ++ PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT; ++ PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT ); ++ PtrIoContext->PtrMasterIrp = NULL; ++ PtrIoContext->PtrSyncEvent = PtrSyncEvent; ++ PtrIoContext->ReadWriteLength = ReadWriteLength; ++ ++ IoSetCompletionRoutine( PtrIrp, ++ SynchronousIo ? ++ Ext2SingleSyncCompletionRoutine: ++ Ext2SingleAsyncCompletionRoutine, ++ PtrIoContext, TRUE, TRUE, TRUE ); ++ ++ // ++ // Setup the next IRP stack location in the associated Irp for the disk ++ // driver beneath us. ++ // ++ PtrIrpNextSp = IoGetNextIrpStackLocation( PtrIrp ); ++ ++ // ++ // Setup the Stack location to do a read from the disk driver. ++ // ++ PtrIrpNextSp->MajorFunction = PtrIrpContext->MajorFunction; ++ if( PtrIrpContext->MajorFunction == IRP_MJ_READ ) ++ { ++ PtrIrpNextSp->Parameters.Read.Length = ReadWriteLength; ++ PtrIrpNextSp->Parameters.Read.ByteOffset = ByteOffset; ++ } ++ else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE ) ++ { ++ PtrIrpNextSp->Parameters.Write.Length = ReadWriteLength; ++ PtrIrpNextSp->Parameters.Write.ByteOffset = ByteOffset; ++ } ++ // ++ // Issue the read / write request ++ // ++ RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); ++ ++ if( SynchronousIo ) ++ { ++ // ++ // Wait for completion... ++ // ++ RC = KeWaitForSingleObject( &PtrIoContext->PtrSyncEvent, ++ Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); ++ ++ RC = STATUS_SUCCESS; ++ } ++ else ++ { ++ RC = STATUS_PENDING; ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrSyncEvent ) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent ); ++ ExFreePool( PtrSyncEvent ); ++ } ++ if( PtrIoContext && !( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) ) ++ { ++ // ++ // This means we are getting out of ++ // this function without doing a read / write ++ // due to an error, maybe... ++ // ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext ); ++ ExFreePool( PtrIoContext ); ++ } ++ } ++ return RC; ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2SingleSyncCompletionRoutine() ++* ++* Description: ++* Synchronous I/O Completion Routine ++* ++* Expected Interrupt Level (for execution) : ++* ++* ? ++* ++* Return Value: NTSTATUS - STATUS_SUCCESS(always) ++* ++*************************************************************************/ ++NTSTATUS Ext2SingleSyncCompletionRoutine( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp, ++ IN PVOID Contxt ++ ) ++{ ++ PEXT2_IO_CONTEXT PtrContext = Contxt; ++ ++ if( Irp->PendingReturned ) ++ IoMarkIrpPending( Irp ); ++ ++ ASSERT( PtrContext ); ++ ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT ); ++ ++ KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE ); ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); ++ ExFreePool( PtrContext ); ++ ++ return STATUS_SUCCESS; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2SingleAsyncCompletionRoutine() ++* ++* Description: ++* Asynchronous I/O Completion Routine ++* ++* Expected Interrupt Level (for execution) : ++* ++* ? ++* ++* Return Value: NTSTATUS - STATUS_SUCCESS(always) ++* ++*************************************************************************/ ++NTSTATUS Ext2SingleAsyncCompletionRoutine( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp, ++ IN PVOID Contxt ++ ) ++{ ++ PEXT2_IO_CONTEXT PtrContext = Contxt; ++ ++ if( Irp->PendingReturned ) ++ IoMarkIrpPending( Irp ); ++ ++ ASSERT( PtrContext ); ++ ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT ); ++ ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); ++ ExFreePool( PtrContext ); ++ ++ return STATUS_SUCCESS; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2MultiSyncCompletionRoutine() ++* ++* Description: ++* Synchronous I/O Completion Routine ++* ++* Expected Interrupt Level (for execution) : ++* ++* ? ++* ++* Return Value: NTSTATUS - STATUS_SUCCESS(always) ++* ++*************************************************************************/ ++NTSTATUS Ext2MultiSyncCompletionRoutine ( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp, ++ IN PVOID Contxt ++ ) ++{ ++ ++ PEXT2_IO_CONTEXT PtrContext = Contxt; ++ ASSERT( PtrContext ); ++ ++ if( Irp->PendingReturned ) ++ { ++ IoMarkIrpPending( Irp ); ++ } ++ ++ if (!NT_SUCCESS( Irp->IoStatus.Status )) ++ { ++ PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status; ++ } ++ ++ if (InterlockedDecrement( &PtrContext->Count ) == 0) ++ { ++ if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) ) ++ { ++ PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength; ++ } ++ else ++ { ++ PtrContext->PtrMasterIrp->IoStatus.Information = 0; ++ } ++ ++ KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE ); ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); ++ ExFreePool( PtrContext ); ++ } ++ ++ // ++ // The master Irp will be automatically completed ++ // when all the associated IRPs are completed ++ // ++ return STATUS_SUCCESS; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2MultiAsyncCompletionRoutine() ++* ++* Description: ++* Asynchronous I/O Completion Routine ++* ++* Expected Interrupt Level (for execution) : ++* ++* ? ++* ++* Return Value: NTSTATUS - STATUS_SUCCESS(always) ++* ++*************************************************************************/ ++NTSTATUS Ext2MultiAsyncCompletionRoutine ( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp, ++ IN PVOID Contxt ++ ) ++{ ++ ++ PEXT2_IO_CONTEXT PtrContext = Contxt; ++ ASSERT( PtrContext ); ++ ++ if( Irp->PendingReturned ) ++ { ++ IoMarkIrpPending( Irp ); ++ } ++ ++ if (!NT_SUCCESS( Irp->IoStatus.Status )) ++ { ++ PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status; ++ } ++ ++ if (InterlockedDecrement( &PtrContext->Count ) == 0) ++ { ++ if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) ) ++ { ++ PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength; ++ } ++ else ++ { ++ PtrContext->PtrMasterIrp->IoStatus.Information = 0; ++ } ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext ); ++ ExFreePool( PtrContext ); ++ } ++ ++ // ++ // The master Irp will be automatically completed ++ // when all the associated IRPs are completed ++ // Returning STATUS_SUCCESS to continue postprocessing... ++ // ++ return STATUS_SUCCESS; ++} diff --cc reactos/drivers/filesystems/ext2/src/metadata.c index 00000000000,00000000000..1369b58fc2c new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/metadata.c @@@ -1,0 -1,0 +1,2837 @@@ ++/************************************************************************* ++* ++* File: metadata.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Should contain code to handle Ext2 Metadata. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++#define EXT2_BUG_CHECK_ID EXT2_FILE_METADATA_IO ++ ++#define DEBUG_LEVEL ( DEBUG_TRACE_METADATA ) ++ ++extern Ext2Data Ext2GlobalData; ++ ++/************************************************************************* ++* ++* Function: Ext2ReadInode() ++* ++* Description: ++* ++* The functions will read in the specifiec inode and return it in a buffer ++* ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* ++* Arguements: ++* ++* ++* ++* Return Value: The Status of the Read IO ++* ++*************************************************************************/ ++ ++NTSTATUS Ext2ReadInode ( ++ PtrExt2VCB PtrVcb, // the Volume Control Block ++ uint32 InodeNo, // The Inode no ++ PEXT2_INODE PtrInode // The Inode Buffer ++ ) ++{ ++ // The Status to be returned... ++ NTSTATUS RC = STATUS_SUCCESS; ++ ++ // The Read Buffer Pointer ++ BYTE * PtrPinnedReadBuffer = NULL; ++ ++ PEXT2_INODE PtrTempInode; ++ ++ // Buffer Control Block ++ PBCB PtrBCB = NULL; ++ ++ LARGE_INTEGER VolumeByteOffset, TempOffset; ++ ++ ULONG LogicalBlockSize = 0; ++ ++ ULONG NumberOfBytesToRead = 0; ++ ULONG Difference = 0; ++ ++ ULONG GroupNo; ++ int Index; ++ ++ try ++ { ++ ASSERT(PtrVcb); ++ ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); ++ ++ // Inode numbers start at 1 and not from 0 ++ // Hence 1 is subtracted from InodeNo to get a zero based index... ++ GroupNo = ( InodeNo - 1 ) / PtrVcb->InodesPerGroup; ++ ++ if( GroupNo >= PtrVcb->NoOfGroups ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo ); ++ DebugTrace(DEBUG_TRACE_MISC, "Only %d groups available on disk", PtrVcb->NoOfGroups ); ++ RC = STATUS_UNSUCCESSFUL; ++ try_return( RC ); ++ } ++ ++ //if( PtrVcb->InodeTableBlock[ GroupNo ] == 0 ) ++ if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo ); ++ RC = STATUS_UNSUCCESSFUL; ++ try_return( RC ); ++ } ++ ++ // Inode numbers start at 1 and not from 0 ++ // Hence 1 is subtracted from InodeNo to get a zero based index... ++ Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup ); ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize; ++ NumberOfBytesToRead = sizeof(EXT2_INODE); // LogicalBlockSize; ++ ++ VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock ++ * LogicalBlockSize + Index * sizeof(EXT2_INODE); ++ //VolumeByteOffset.QuadPart = PtrVcb->InodeTableBlock[ GroupNo ] * LogicalBlockSize + ++ // Index * sizeof(EXT2_INODE); ++ ++ TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize ); ++ if( TempOffset.QuadPart != VolumeByteOffset.QuadPart ) ++ { ++ // TempOffset.QuadPart -= LogicalBlockSize; ++ Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize ); ++ VolumeByteOffset.QuadPart -= Difference; ++ NumberOfBytesToRead += Difference; ++ } ++ ++ NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); ++ ++ if( NumberOfBytesToRead > LogicalBlockSize ) ++ { ++ // Multiple blocks being read in... ++ // Can cause overlap ++ // Watch out!!!! ++ Ext2BreakPoint(); ++ } ++ ++ ++ ++ if (!CcMapData( PtrVcb->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrBCB, ++ (PVOID*)&PtrPinnedReadBuffer )) ++ { ++ RC = STATUS_UNSUCCESSFUL; ++ try_return( RC ); ++ } ++ else ++ { ++ PtrTempInode = (PEXT2_INODE) ( PtrPinnedReadBuffer + Difference ); ++ RtlCopyMemory( PtrInode, PtrTempInode , sizeof(EXT2_INODE) ); ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrBCB ) ++ { ++ CcUnpinData( PtrBCB ); ++ PtrBCB = NULL; ++ } ++ ++ } ++ return RC; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2InitializeFCBInodeInfo() ++* ++* Description: ++* The functions will initialize the FCB with its i-node info ++* provided it hasn't been initialized as yet... ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Arguements: ++* Pointer to FCB ++* ++* Return Value: None ++* ++*************************************************************************/ ++void Ext2InitializeFCBInodeInfo ( ++ PtrExt2FCB PtrFCB ) ++{ ++ PtrExt2VCB PtrVCB = NULL; ++ EXT2_INODE Inode; ++ int i; ++ ULONG LogicalBlockSize; ++ ++ PtrVCB = PtrFCB->PtrVCB; ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ if( !Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ) ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "Reading in the i-node no %d", PtrFCB->INodeNo ); ++ ++ Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); ++ ++ for( i = 0; i < EXT2_N_BLOCKS ; i++ ) ++ { ++ PtrFCB->IBlock[i] = Inode.i_block[ i ]; ++ } ++ ++ PtrFCB->CreationTime.QuadPart = ( __int64 )Inode.i_ctime * 10000000; ++ PtrFCB->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; ++ PtrFCB->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_atime * 10000000); ++ PtrFCB->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_mtime * 10000000); ++ ++ ++ PtrFCB->LinkCount = Inode.i_links_count; ++ ++ // Getting the file type... ++ if( ! Ext2IsModeRegularFile( Inode.i_mode ) ) ++ { ++ // Not a reqular file... ++ if( Ext2IsModeDirectory( Inode.i_mode) ) ++ { ++ // Directory... ++ Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ); ++ } ++ else ++ { ++ // Special File... ++ // Treated with respect... ;) ++ // ++ Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ); ++ } ++ ++ } ++ if( Ext2IsModeHidden( Inode.i_mode ) ) ++ { ++ Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ); ++ } ++ if( Ext2IsModeReadOnly( Inode.i_mode ) ) ++ { ++ Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ); ++ } ++ ++ ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = Inode.i_size; ++ Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ); ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart = Inode.i_blocks * 512; ++ ++ if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) ++ { ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart -= LogicalBlockSize / 512; ++ } ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [metadata]", Inode ); ++ } ++} ++ ++/************************************************************************* ++* ++* Function: Ext2AllocInode() ++* ++* Description: ++* The functions will allocate a new on-disk i-node ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* ++* Arguements: ++* Parent Inode no ++* ++* Return Value: The new i-node no or zero ++* ++*************************************************************************/ ++ULONG Ext2AllocInode( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ ULONG ParentINodeNo ) ++{ ++ ULONG InodeNo = 0; ++ ++ // Buffer Control Block ++ PBCB PtrBitmapBCB = NULL; ++ BYTE * PtrBitmapBuffer = NULL; ++ ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG LogicalBlockSize = 0; ++ ULONG NumberOfBytesToRead = 0; ++ ++ if( PtrVCB->FreeInodesCount == 0) ++ { ++ // ++ // No Free Inodes left... ++ // Fail request... ++ // ++ return 0; ++ } ++ ++ try ++ { ++ // unsigned int DescIndex ; ++ BOOLEAN Found = FALSE; ++ ULONG Block; ++ ULONG GroupNo; ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ ) ++ { ++ if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount ) ++ break; ++ } ++ ++ VolumeByteOffset.QuadPart = ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock * LogicalBlockSize; ++ ++ NumberOfBytesToRead = PtrVCB->InodesCount / PtrVCB->NoOfGroups; ++ ++ if( NumberOfBytesToRead % 8 ) ++ { ++ NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1; ++ } ++ else ++ { ++ NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ; ++ } ++ ++ for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); ++ Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize) ++ { ++ // ++ // Read in the bitmap block... ++ // ++ ULONG i, j; ++ BYTE Bitmap; ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, //NumberOfBytesToRead, ++ TRUE, ++ &PtrBitmapBCB, ++ (PVOID*)&PtrBitmapBuffer ) ) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ return 0; ++ } ++ ++ // ++ // Is there a free inode... ++ // ++ for( i = 0; !Found && i < LogicalBlockSize && ++ i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ ) ++ { ++ Bitmap = PtrBitmapBuffer[i]; ++ if( Bitmap != 0xff ) ++ { ++ // ++ // Found a free inode... ++ for( j = 0; !Found && j < 8; j++ ) ++ { ++ if( ( Bitmap & 0x01 ) == 0 ) ++ { ++ // ++ // Found... ++ Found = TRUE; ++ ++ // Inode numbers start at 1 and not from 0 ++ // Hence 1 is addded to j ++ InodeNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 + ++ ( GroupNo * PtrVCB->InodesPerGroup ); ++ ++ // Update the inode on the disk... ++ Bitmap = 1 << j; ++ PtrBitmapBuffer[i] |= Bitmap; ++ ++ CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); ++ ++ // ++ // Should update the bitmaps in the other groups too... ++ // ++ break; ++ } ++ Bitmap = Bitmap >> 1; ++ } ++ } ++ } ++ // ++ // Unpin the BCB... ++ // ++ if( PtrBitmapBCB ) ++ { ++ CcUnpinData( PtrBitmapBCB ); ++ PtrBitmapBCB = NULL; ++ } ++ } ++ ++ { ++ // ++ // Updating the Inode count in the Group Descriptor... ++ // ++ PBCB PtrDescriptorBCB = NULL; ++ PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; ++ ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount--; ++ ++ if( PtrVCB->LogBlockSize ) ++ { ++ // First block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize; ++ } ++ else ++ { ++ // Second block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize * 2; ++ } ++ NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); ++ NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); ++ ++ if (!CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrDescriptorBCB , ++ (PVOID*)&PtrGroupDescriptor )) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ // ++ // Ignore this error... ++ // Not fatal... ++ } ++ else ++ { ++ PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; ++ // ++ // Not synchronously flushing this information... ++ // Lazy writing will do... ++ // ++ CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); ++ CcUnpinData( PtrDescriptorBCB ); ++ PtrDescriptorBCB = NULL; ++ } ++ } ++ ++ ++ // ++ // Update the Inode count... ++ // in the Super Block... ++ // ++ { ++ // Ext2 Super Block information... ++ PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; ++ PBCB PtrSuperBlockBCB = NULL; ++ ++ PtrVCB->FreeInodesCount--; ++ // Reading in the super block... ++ VolumeByteOffset.QuadPart = 1024; ++ ++ // THis shouldn't be more than a block in size... ++ NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrSuperBlockBCB, ++ (PVOID*)&PtrSuperBlock ) ) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ } ++ else ++ { ++ PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount; ++ CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); ++ if( PtrSuperBlockBCB ) ++ { ++ CcUnpinData( PtrSuperBlockBCB ); ++ PtrSuperBlockBCB = NULL; ++ } ++ ++ } ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrBitmapBCB ) ++ { ++ CcUnpinData( PtrBitmapBCB ); ++ PtrBitmapBCB = NULL; ++ } ++ } ++ DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating an inode - I-Node no : %ld", InodeNo ); ++ ++ return InodeNo; ++ ++} ++ ++/************************************************************************* ++* ++* Function: Ext2DeallocInode() ++* ++* Description: ++* The functions will deallocate an i-node ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: Success / Failure... ++* ++*************************************************************************/ ++BOOLEAN Ext2DeallocInode( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ ULONG INodeNo ) ++{ ++ BOOLEAN RC = TRUE; ++ ++ // Buffer Control Block ++ PBCB PtrBitmapBCB = NULL; ++ BYTE * PtrBitmapBuffer = NULL; ++ ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG LogicalBlockSize = 0; ++ ++ DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating an inode - I-Node no : %ld", INodeNo ); ++ ++ try ++ { ++ ULONG BlockIndex ; ++ ULONG BitmapIndex; ++ ULONG GroupNo; ++ BYTE Bitmap; ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ GroupNo = INodeNo / PtrVCB->InodesPerGroup; ++ INodeNo = INodeNo % PtrVCB->InodesPerGroup; ++ ++ BitmapIndex = (INodeNo-1) / 8; ++ Bitmap = 1 << ( (INodeNo-1) % 8 ); ++ BlockIndex = BitmapIndex / LogicalBlockSize; ++ // Adjusting to index into the Logical block that contains the bitmap ++ BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize ); ++ ++ VolumeByteOffset.QuadPart = ++ ( PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock + BlockIndex ) ++ * LogicalBlockSize; ++ ++ // ++ // Read in the bitmap block... ++ // ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, // Just the block that contains the bitmap will do... ++ TRUE, // Can Wait... ++ &PtrBitmapBCB, ++ (PVOID*)&PtrBitmapBuffer ) ) ++ { ++ // Unable to Pin the data into the cache... ++ try_return (RC = FALSE); ++ } ++ ++ // ++ // Locate the inode... ++ // This inode is in the byte PtrBitmapBuffer[ BitmapIndex ] ++ if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0) ++ { ++ // This shouldn't have been so... ++ // The inode was never allocated! ++ // How to deallocate something that hasn't been allocated? ++ // Hmmm... ;) ++ // Ignore this error... ++ try_return (RC = TRUE); ++ } ++ ++ ++ // Setting the bit for the inode... ++ PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap); ++ ++ // Update the cache... ++ CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); ++ ++ // Save up the BCB for forcing a synchronous write... ++ // Before completing the IRP... ++ Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); ++ ++ ++ if( PtrBitmapBCB ) ++ { ++ CcUnpinData( PtrBitmapBCB ); ++ PtrBitmapBCB = NULL; ++ } ++ ++ { ++ // ++ // Updating the Inode count in the Group Descriptor... ++ // ++ PBCB PtrDescriptorBCB = NULL; ++ PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; ++ ULONG NumberOfBytesToRead = 0; ++ ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount++; ++ ++ if( PtrVCB->LogBlockSize ) ++ { ++ // First block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize; ++ } ++ else ++ { ++ // Second block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize * 2; ++ } ++ NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); ++ NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); ++ ++ if (!CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrDescriptorBCB , ++ (PVOID*)&PtrGroupDescriptor )) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ // ++ // Ignore this error... ++ // Not fatal... ++ } ++ else ++ { ++ PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; ++ // ++ // Not synchronously flushing this information... ++ // Lazy writing will do... ++ // ++ CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); ++ CcUnpinData( PtrDescriptorBCB ); ++ PtrDescriptorBCB = NULL; ++ } ++ } ++ ++ ++ // ++ // Update the Inode count... ++ // in the Super Block ++ // and in the VCB ++ // ++ { ++ // Ext2 Super Block information... ++ PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; ++ PBCB PtrSuperBlockBCB = NULL; ++ ULONG NumberOfBytesToRead = 0; ++ ++ PtrVCB->FreeInodesCount++; ++ ++ // Reading in the super block... ++ VolumeByteOffset.QuadPart = 1024; ++ NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrSuperBlockBCB, ++ (PVOID*)&PtrSuperBlock ) ) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ } ++ else ++ { ++ PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount; ++ CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); ++ if( PtrSuperBlockBCB ) ++ { ++ CcUnpinData( PtrSuperBlockBCB ); ++ PtrSuperBlockBCB = NULL; ++ } ++ ++ } ++ } ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrBitmapBCB ) ++ { ++ CcUnpinData( PtrBitmapBCB ); ++ PtrBitmapBCB = NULL; ++ } ++ } ++ return RC; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2WriteInode() ++* ++* Description: ++* The functions will write an i-node to disk ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* ++* Return Value: Success / Failure... ++* ++*************************************************************************/ ++NTSTATUS Ext2WriteInode( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVcb, // the Volume Control Block ++ uint32 InodeNo, // The Inode no ++ PEXT2_INODE PtrInode // The Inode Buffer ++ ) ++{ ++ // The Status to be returned... ++ NTSTATUS RC = STATUS_SUCCESS; ++ ++ // The Read Buffer Pointer ++ BYTE * PtrPinnedBuffer = NULL; ++ ++ PEXT2_INODE PtrTempInode; ++ ++ // Buffer Control Block ++ PBCB PtrBCB = NULL; ++ ++ LARGE_INTEGER VolumeByteOffset, TempOffset; ++ ++ ULONG LogicalBlockSize = 0; ++ ULONG NumberOfBytesToRead = 0; ++ ULONG Difference = 0; ++ ULONG GroupNo; ++ int Index; ++ ++ try ++ { ++ DebugTrace( DEBUG_TRACE_SPECIAL, "Writing and updating an inode - I-Node no : %ld", InodeNo ); ++ ++ ASSERT(PtrVcb); ++ ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); ++ GroupNo = InodeNo / PtrVcb->InodesPerGroup; ++ ++ if( GroupNo >= PtrVcb->NoOfGroups ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo ); ++ DebugTrace(DEBUG_TRACE_MISC, "Only %d groups available on disk", PtrVcb->NoOfGroups ); ++ RC = STATUS_UNSUCCESSFUL; ++ try_return( RC ); ++ } ++ ++ if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo ); ++ RC = STATUS_UNSUCCESSFUL; ++ try_return( RC ); ++ } ++ ++ Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup ); ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize; ++ NumberOfBytesToRead = sizeof(EXT2_INODE); ++ ++ VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock ++ * LogicalBlockSize + Index * sizeof(EXT2_INODE); ++ ++ TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize ); ++ if( TempOffset.QuadPart != VolumeByteOffset.QuadPart ) ++ { ++ // TempOffset.QuadPart -= LogicalBlockSize; ++ Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize ); ++ VolumeByteOffset.QuadPart -= Difference; ++ NumberOfBytesToRead += Difference; ++ } ++ ++ NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); ++ ++ if( NumberOfBytesToRead > LogicalBlockSize ) ++ { ++ // Multiple blocks being read in... ++ // Can cause overlap ++ // Watch out!!!! ++ Ext2BreakPoint(); ++ } ++ ++ if( !CcPinRead( PtrVcb->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, // Can Wait... ++ &PtrBCB, ++ (PVOID*)&PtrPinnedBuffer ) ) ++ { ++ RC = STATUS_UNSUCCESSFUL; ++ try_return( RC ); ++ } ++ else ++ { ++ RtlCopyMemory( PtrPinnedBuffer + Difference, PtrInode, sizeof(EXT2_INODE) ); ++ CcSetDirtyPinnedData( PtrBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrBCB, PtrVcb->PtrStreamFileObject ); ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrBCB ) ++ { ++ CcUnpinData( PtrBCB ); ++ PtrBCB = NULL; ++ } ++ ++ } ++ return RC; ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2MakeNewDirectoryEntry() ++* ++* Description: ++* The functions will make a new directory entry in a directory file... ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* ++* Return Value: Success / Failure... ++* ++*************************************************************************/ ++BOOLEAN Ext2MakeNewDirectoryEntry( ++ PtrExt2IrpContext PtrIrpContext, // The Irp context ++ PtrExt2FCB PtrParentFCB, // Parent Folder FCB ++ PFILE_OBJECT PtrFileObject, // Parent Folder Object ++ PUNICODE_STRING PtrName, // New entry's name ++ ULONG Type, // The type of the new entry ++ ULONG NewInodeNo) // The inode no of the new entry... ++{ ++ PBCB PtrLastBlockBCB = NULL; ++ BYTE * PtrLastBlock = NULL; ++ EXT2_DIR_ENTRY DirEntry; ++ PEXT2_DIR_ENTRY PtrTempDirEntry; ++ ++ ULONG BlockNo = 0; ++ ULONG i; ++ PtrExt2VCB PtrVCB; ++ LARGE_INTEGER VolumeByteOffset; ++ unsigned long LogicalBlockSize = 0; ++ unsigned long NumberOfBytesToRead = 0; ++ BOOLEAN RC = FALSE; ++ ++ USHORT HeaderLength = sizeof( EXT2_DIR_ENTRY ); ++ USHORT NewEntryLength = 0; ++ USHORT MinLength = 0; ++ #define ActualLength (PtrTempDirEntry->rec_len) ++ #define NameLength (PtrTempDirEntry->name_len) ++ ++ try ++ { ++ ASSERT( PtrFileObject ); ++ ++ DebugTrace( DEBUG_TRACE_SPECIAL, "Making directory entry: %S", PtrName->Buffer ); ++ ++ PtrVCB = PtrParentFCB->PtrVCB; ++ AssertVCB( PtrVCB); ++ ++ HeaderLength = sizeof( EXT2_DIR_ENTRY ) - ++ (sizeof( char ) * EXT2_NAME_LEN); ++ // 1. Setting up the entry... ++ NewEntryLength = sizeof( EXT2_DIR_ENTRY ) - ( sizeof( char ) * ( EXT2_NAME_LEN - (PtrName->Length / 2) ) ); ++ // Length should be a multiplicant of 4 ++ NewEntryLength = ((NewEntryLength + 3 ) & 0xfffffffc); ++ ++ RtlZeroMemory( &DirEntry, sizeof( EXT2_DIR_ENTRY ) ); ++ ++ DirEntry.file_type = (BYTE) Type; ++ DirEntry.inode = NewInodeNo; ++ DirEntry.name_len = (BYTE)(PtrName->Length / 2 ); // Does not include a NULL ++ ++ // DirEntry.rec_len = (USHORT) NewEntryLength; ++ ++ for( i = 0; ; i++ ) ++ { ++ if( i < (ULONG)( PtrName->Length / 2 ) ) ++ { ++ DirEntry.name[i] = (CHAR) PtrName->Buffer[i]; ++ } ++ else ++ { ++ //DirEntry.name[i] = 0; // Entry need not be zero terminated... ++ break; ++ } ++ } ++ ++ // ++ // 2. Read the block in the directory... ++ // Initiate Caching... ++ if ( PtrFileObject->PrivateCacheMap == NULL ) ++ { ++ CcInitializeCacheMap( ++ PtrFileObject, ++ (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), ++ TRUE, // We utilize pin access for directories ++ &(Ext2GlobalData.CacheMgrCallBacks), // callbacks ++ PtrParentFCB ); // The context used in callbacks ++ } ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ if( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart > 0 ) ++ { ++ BlockNo = (ULONG) ( (PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) / LogicalBlockSize) ; ++ } ++ else ++ { ++ // This directory doesn't have any data blocks... ++ // Allocate a new block... ++ if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ else ++ { ++ // Bring in the newly allocated block to the cache... ++ VolumeByteOffset.QuadPart = 0; ++ ++ if( !CcPreparePinWrite( ++ PtrFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Zero out the block... ++ TRUE, // Can Wait... ++ &PtrLastBlockBCB, ++ (PVOID*)&PtrLastBlock ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ ++ DirEntry.rec_len = (USHORT)LogicalBlockSize; ++ RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); ++ CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); ++ try_return( RC = TRUE ); ++ } ++ } ++ ++ VolumeByteOffset.QuadPart = BlockNo * LogicalBlockSize; ++ CcMapData( PtrFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrLastBlockBCB, ++ (PVOID*)&PtrLastBlock ); ++ ++ for( i = 0 ; i < LogicalBlockSize; ) ++ { ++ PtrTempDirEntry = (PEXT2_DIR_ENTRY) &PtrLastBlock[ i ]; ++ ++ MinLength = HeaderLength + NameLength; ++ MinLength = ( HeaderLength + NameLength + 3 ) & 0xfffffffc; ++ ++ ++ if( PtrTempDirEntry->rec_len == 0 ) ++ { ++ if( i == 0 ) ++ { ++ // Must be an empty Block... ++ // Insert here... ++ // ---------------->>> ++ ++ CcPinMappedData( PtrFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrLastBlockBCB ); ++ ++ DirEntry.rec_len = (USHORT)LogicalBlockSize; ++ ++ RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); ++ CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); ++ try_return( RC = TRUE ); ++ } ++ else ++ { ++ // This shouldn't be so... ++ // Something is wrong... ++ // Fail this request... ++ try_return( RC = FALSE ); ++ } ++ } ++ if( ActualLength - MinLength >= NewEntryLength ) ++ { ++ // Insert here... ++ // ----------------> ++ ++ // Getting ready for updation... ++ CcPinMappedData( PtrFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrLastBlockBCB ); ++ ++ ++ DirEntry.rec_len = ActualLength - MinLength; ++ ++ // Updating the current last entry ++ PtrTempDirEntry->rec_len = MinLength; ++ i += PtrTempDirEntry->rec_len; ++ ++ // Making the new entry... ++ RtlCopyBytes( (PtrLastBlock + i) , &DirEntry, NewEntryLength); ++ CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); ++ try_return( RC = TRUE ); ++ ++ } ++ i += PtrTempDirEntry->rec_len; ++ } ++ ++ // Will have to allocate a new block... ++ // Old block does not have enough space.. ++ if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ else ++ { ++ // unpin the previously pinned block ++ CcUnpinData( PtrLastBlockBCB ); ++ PtrLastBlockBCB = NULL; ++ ++ // Bring in the newly allocated block to the cache... ++ VolumeByteOffset.QuadPart += LogicalBlockSize; ++ if( !CcPreparePinWrite( ++ PtrFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Zero out the block... ++ TRUE, // Can Wait... ++ &PtrLastBlockBCB, ++ (PVOID*)&PtrLastBlock ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ ++ DirEntry.rec_len = (USHORT)LogicalBlockSize; ++ RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength); ++ CcSetDirtyPinnedData( PtrLastBlockBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject ); ++ try_return( RC = TRUE ); ++ } ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrLastBlockBCB ) ++ { ++ CcUnpinData( PtrLastBlockBCB ); ++ PtrLastBlockBCB = NULL; ++ } ++ } ++ if( RC == FALSE ) ++ { ++ DebugTrace( DEBUG_TRACE_ERROR, "Failed to making directory entry: %S", PtrName->Buffer ); ++ } ++ return RC; ++} ++ ++ ++BOOLEAN Ext2FreeDirectoryEntry( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2FCB PtrParentFCB, ++ PUNICODE_STRING PtrName) ++{ ++ ++ PBCB PtrDataBlockBCB = NULL; ++ BYTE * PtrDataBlock = NULL; ++ PFILE_OBJECT PtrFileObject = NULL; ++ PEXT2_DIR_ENTRY PtrTempDirEntry; ++ LONGLONG ByteOffset = 0; ++ PtrExt2VCB PtrVCB; ++ LARGE_INTEGER VolumeByteOffset; ++ unsigned long LogicalBlockSize = 0; ++ BOOLEAN RC = FALSE; ++ ++ ++ try ++ { ++ DebugTrace( DEBUG_TRACE_SPECIAL, "Freeing directory entry: %S", PtrName->Buffer ); ++ ++ PtrVCB = PtrParentFCB->PtrVCB; ++ AssertVCB( PtrVCB); ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject; ++ if( PtrFileObject == NULL ) ++ { ++ return FALSE; ++ } ++ ++ ++ // ++ // 1. Read the block in the directory... ++ // Initiate Caching... ++ if ( PtrFileObject->PrivateCacheMap == NULL ) ++ { ++ CcInitializeCacheMap( ++ PtrFileObject, ++ (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), ++ TRUE, // We utilize pin access for directories ++ &(Ext2GlobalData.CacheMgrCallBacks), // callbacks ++ PtrParentFCB ); // The context used in callbacks ++ } ++ ++ for( ByteOffset = 0; ++ ByteOffset < PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart; ++ ByteOffset += LogicalBlockSize ) ++ { ++ ULONG Index = 0; ++ PEXT2_DIR_ENTRY PtrDirEntry = NULL; ++ ++ ++ VolumeByteOffset.QuadPart = ByteOffset; ++ ++ CcPinRead( PtrFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrDataBlockBCB, ++ (PVOID*)&PtrDataBlock ); ++ while( Index < LogicalBlockSize ) ++ { ++ ULONG i; ++ // Parse... ++ PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrDataBlock[ Index ]; ++ Index += PtrDirEntry->rec_len; ++ ++ if( PtrDirEntry->inode == 0 ) ++ { ++ // This is a deleted entry... ++ continue; ++ } ++ if( ( PtrName->Length/2 ) != PtrDirEntry->name_len ) ++ continue; ++ for( i = 0; ; i++ ) ++ { ++ if( PtrDirEntry->name_len == i ) ++ { ++ // Remove the entry by setting the inode no to zero ++ PtrDirEntry->inode = 0; ++ ++ // Update the disk ++ CcSetDirtyPinnedData( PtrDataBlockBCB , NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrDataBlockBCB, PtrFileObject ); ++ CcUnpinData( PtrDataBlockBCB ); ++ PtrDataBlockBCB = NULL; ++ ++ // Return to caller... ++ try_return( RC = TRUE ); ++ } ++ if( PtrName->Buffer[i] != PtrDirEntry->name[i] ) ++ { ++ break; ++ } ++ } ++ } ++ CcUnpinData( PtrDataBlockBCB ); ++ PtrDataBlockBCB = NULL; ++ } ++ try_return( RC = FALSE ); ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrDataBlockBCB ) ++ { ++ CcUnpinData( PtrDataBlockBCB ); ++ PtrDataBlockBCB = NULL; ++ } ++ } ++ return RC; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2AddBlockToFile() ++* ++* Description: ++* The functions will add a block to a file... ++* It will update the allocation size but not the file size... ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* ++* Return Value: Success / Failure... ++* ++*************************************************************************/ ++BOOLEAN Ext2AddBlockToFile( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ PtrExt2FCB PtrFCB, ++ PFILE_OBJECT PtrFileObject, ++ BOOLEAN UpdateFileSize) ++{ ++ BOOLEAN RC = TRUE; ++ ++ ULONG NewBlockNo = 0; ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG LogicalBlockSize = 0; ++ ULONG NoOfBlocks = 0; ++ EXT2_INODE Inode; ++ ++ ULONG DirectBlocks = 0; ++ ULONG SingleIndirectBlocks = 0; ++ ULONG DoubleIndirectBlocks = 0; ++ ULONG TripleIndirectBlocks = 0; ++ ++ ULONG *PtrSIBBuffer = NULL; ++ PBCB PtrSIBBCB = NULL; ++ ULONG *PtrDIBBuffer = NULL; ++ PBCB PtrDIBBCB = NULL; ++ ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ DirectBlocks = EXT2_NDIR_BLOCKS ; ++ SingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG ); ++ DoubleIndirectBlocks = SingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); ++ TripleIndirectBlocks = DoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); ++ ++ try ++ { ++ if( PtrFCB && PtrFCB->FCBName->ObjectName.Length ) ++ { ++ DebugTrace( DEBUG_TRACE_SPECIAL, "Adding Blocks to file %S", PtrFCB->FCBName->ObjectName.Buffer ); ++ } ++ ++ Ext2InitializeFCBInodeInfo( PtrFCB ); ++ ++ // Allocate a block... ++ NewBlockNo = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); ++ ++ if( NewBlockNo == 0 ) ++ { ++ try_return (RC = FALSE ); ++ } ++ ++ // No of blocks CURRENTLY allocated... ++ NoOfBlocks = (ULONG) PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart / LogicalBlockSize; ++ ++ ++ if( NoOfBlocks < EXT2_NDIR_BLOCKS ) ++ { ++ // ++ // A direct data block will do... ++ // ++ ++ PtrFCB->IBlock[ NoOfBlocks ] = NewBlockNo; ++ ++ // Update the inode... ++ Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); ++ Inode.i_block[ NoOfBlocks ] = NewBlockNo; ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; ++ if( UpdateFileSize ) ++ { ++ Inode.i_size += LogicalBlockSize; ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; ++ } ++ ++ ++ if( PtrFileObject->PrivateCacheMap != NULL) ++ { ++ // ++ // Caching has been initiated... ++ // Let the Cache manager in on these changes... ++ // ++ CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); ++ } ++ ++ ++ // Updating the inode... ++ if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ try_return (RC = TRUE); ++ } ++ else ++ { ++ try_return (RC = FALSE ); ++ } ++ ++ } ++ else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks) ) ++ { ++ // ++ // A single indirect data block will do... ++ Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); ++ ++ if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 ) ++ { ++ // A Single Indirect block should be allocated as well!! ++ PtrFCB->IBlock[ EXT2_IND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); ++ if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 ) ++ { ++ try_return (RC = FALSE ); ++ } ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ ++ // Bring in the new block to the cache ++ // Zero it out ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; ++ ++ if( !CcPreparePinWrite( ++ PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Zero out the block... ++ TRUE, // Can Wait... ++ &PtrSIBBCB, ++ (PVOID*)&PtrSIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ else ++ { ++ // Just bring in the SIB to the cache ++ ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Can Wait... ++ &PtrSIBBCB, ++ (PVOID*)&PtrSIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ ++ // Update the inode... ++ ++ Inode.i_block[ EXT2_IND_BLOCK ] = PtrFCB->IBlock[ EXT2_IND_BLOCK ]; ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; ++ if( UpdateFileSize ) ++ { ++ Inode.i_size += LogicalBlockSize; ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; ++ } ++ if( PtrFileObject->PrivateCacheMap != NULL) ++ { ++ // ++ // Caching has been initiated... ++ // Let the Cache manager in on these changes... ++ // ++ CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); ++ } ++ ++ if( !NT_SUCCESS( Ext2WriteInode( ++ PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ try_return (RC = FALSE ); ++ } ++ ++ ++ // Update the SIB... ++ PtrSIBBuffer[ NoOfBlocks - DirectBlocks ] = NewBlockNo; ++ CcSetDirtyPinnedData( PtrSIBBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); ++ ++ try_return (RC = TRUE); ++ ++ } ++ else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks + DoubleIndirectBlocks ) ) ++ { ++ // ++ // A double indirect block will do... ++ // ++ ULONG SBlockNo; ++ ULONG BlockNo; ++ ++ Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); ++ ++ if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) ++ { ++ // A double indirect pointer block should be allocated as well!! ++ PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); ++ if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) ++ { ++ try_return (RC = FALSE ); ++ } ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ ++ // Bring in the new block to the cache ++ // Zero it out ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; ++ ++ if( !CcPreparePinWrite( ++ PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Zero out the block... ++ TRUE, // Can Wait... ++ &PtrDIBBCB, ++ (PVOID*)&PtrDIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ else ++ { ++ // Just bring in the DIB to the cache ++ ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Can Wait... ++ &PtrDIBBCB, ++ (PVOID*)&PtrDIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ ++ // See if a single indirect 'pointer' block ++ // should also be allocated... ++ BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks ); ++ SBlockNo = BlockNo / SingleIndirectBlocks; ++ if( BlockNo % SingleIndirectBlocks ) ++ { ++ // A single indirect 'pointer' block ++ // should also be allocated... ++ PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); ++ CcSetDirtyPinnedData( PtrDIBBCB, NULL ); ++ VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; ++ ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ ++ if( !CcPreparePinWrite( ++ PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Zero out the block... ++ TRUE, // Can Wait... ++ &PtrSIBBCB, ++ (PVOID*)&PtrSIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ else ++ { ++ VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Can Wait... ++ &PtrSIBBCB, ++ (PVOID*)&PtrSIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ BlockNo = BlockNo % SingleIndirectBlocks; ++ ++ // Update the inode... ++ ++ Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ]; ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; ++ if( UpdateFileSize ) ++ { ++ Inode.i_size += LogicalBlockSize; ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; ++ } ++ if( PtrFileObject->PrivateCacheMap != NULL) ++ { ++ // ++ // Caching has been initiated... ++ // Let the Cache manager in on these changes... ++ // ++ CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); ++ } ++ ++ if( !NT_SUCCESS( Ext2WriteInode( ++ PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ try_return (RC = FALSE ); ++ } ++ ++ ++ // Update the SIB... ++ PtrSIBBuffer[ BlockNo ] = NewBlockNo; ++ CcSetDirtyPinnedData( PtrSIBBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); ++ Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject ); ++ ++ try_return (RC = TRUE); ++ ++ } ++ else ++ { ++ // ++ // A Triple Indirect block is required ++ // ++ ULONG SBlockNo; ++ ULONG BlockNo; ++ ++ // This is not supported as yet... ++ try_return (RC = FALSE); ++ ++ Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ); ++ ++ if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] == 0 ) ++ { ++ // A double indirect pointer block should be allocated as well!! ++ PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); ++ if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 ) ++ { ++ try_return (RC = FALSE ); ++ } ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ ++ // Bring in the new block to the cache ++ // Zero it out ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; ++ ++ if( !CcPreparePinWrite( ++ PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Zero out the block... ++ TRUE, // Can Wait... ++ &PtrDIBBCB, ++ (PVOID*)&PtrDIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ else ++ { ++ // Just bring in the DIB to the cache ++ ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Can Wait... ++ &PtrDIBBCB, ++ (PVOID*)&PtrDIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ ++ // See if a single indirect 'pointer' block ++ // should also be allocated... ++ BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks ); ++ SBlockNo = BlockNo / SingleIndirectBlocks; ++ if( BlockNo % SingleIndirectBlocks ) ++ { ++ // A single indirect 'pointer' block ++ // should also be allocated... ++ PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 ); ++ CcSetDirtyPinnedData( PtrDIBBCB, NULL ); ++ VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; ++ ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ ++ if( !CcPreparePinWrite( ++ PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Zero out the block... ++ TRUE, // Can Wait... ++ &PtrSIBBCB, ++ (PVOID*)&PtrSIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ else ++ { ++ VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize; ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Can Wait... ++ &PtrSIBBCB, ++ (PVOID*)&PtrSIBBuffer ) ) ++ { ++ try_return( RC = FALSE ); ++ } ++ } ++ BlockNo = BlockNo % SingleIndirectBlocks; ++ ++ // Update the inode... ++ ++ Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ]; ++ Inode.i_blocks += ( LogicalBlockSize / 512 ); ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize; ++ if( UpdateFileSize ) ++ { ++ Inode.i_size += LogicalBlockSize; ++ PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize; ++ } ++ if( PtrFileObject->PrivateCacheMap != NULL) ++ { ++ // ++ // Caching has been initiated... ++ // Let the Cache manager in on these changes... ++ // ++ CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); ++ } ++ ++ if( !NT_SUCCESS( Ext2WriteInode( ++ PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ try_return (RC = FALSE ); ++ } ++ ++ ++ // Update the SIB... ++ PtrSIBBuffer[ BlockNo ] = NewBlockNo; ++ CcSetDirtyPinnedData( PtrSIBBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject ); ++ Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject ); ++ ++ try_return (RC = TRUE); ++ ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrSIBBCB ) ++ { ++ CcUnpinData( PtrSIBBCB ); ++ PtrSIBBCB = NULL; ++ } ++ if( PtrDIBBCB ) ++ { ++ CcUnpinData( PtrDIBBCB ); ++ PtrDIBBCB = NULL; ++ } ++ } ++ return RC; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2AllocBlock() ++* ++* Description: ++* The functions will allocate a new block ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* ++* Return Value: Success / Failure... ++* ++*************************************************************************/ ++ULONG Ext2AllocBlock( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ ULONG Count) ++{ ++ // Buffer Control Block ++ PBCB PtrBitmapBCB = NULL; ++ BYTE * PtrBitmapBuffer = NULL; ++ ULONG BlockNo = 0; ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG LogicalBlockSize = 0; ++ ULONG NumberOfBytesToRead = 0; ++ ++ if( PtrVCB->FreeBlocksCount == 0 ) ++ { ++ // ++ // No Free Block left... ++ // Fail request... ++ // ++ return 0; ++ } ++ ++ try ++ { ++ BOOLEAN Found = FALSE; ++ ULONG Block; ++ ULONG GroupNo; ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ ) ++ { ++ if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount ) ++ break; ++ } ++ ++ VolumeByteOffset.QuadPart = ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock * LogicalBlockSize; ++ ++ NumberOfBytesToRead = PtrVCB->BlocksCount / PtrVCB->NoOfGroups; ++ ++ if( NumberOfBytesToRead % 8 ) ++ { ++ NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1; ++ } ++ else ++ { ++ NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ; ++ } ++ ++ ++ for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); ++ Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize) ++ { ++ // ++ // Read in the block bitmap block... ++ ULONG i, j; ++ BYTE Bitmap; ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, // NumberOfBytesToRead, ++ TRUE, ++ &PtrBitmapBCB, ++ (PVOID*)&PtrBitmapBuffer ) ) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ try_return( BlockNo = 0 ); ++ } ++ ++ // ++ // Is there a free block... ++ // ++ for( i = 0; !Found && i < LogicalBlockSize && ++ i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ ) ++ { ++ Bitmap = PtrBitmapBuffer[i]; ++ if( Bitmap != 0xff ) ++ { ++ // ++ // Found a free block... ++ for( j = 0; !Found && j < 8; j++ ) ++ { ++ if( ( Bitmap & 0x01 ) == 0 ) ++ { ++ // ++ // Found... ++ Found = TRUE; ++ BlockNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 ++ + ( GroupNo * PtrVCB->BlocksPerGroup ); ++ ++ Bitmap = 1 << j; ++ PtrBitmapBuffer[i] |= Bitmap; ++ ++ CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); ++ // ++ // Should update the bitmaps in the other groups too... ++ // ++ break; ++ } ++ Bitmap = Bitmap >> 1; ++ } ++ } ++ } ++ // ++ // Unpin the BCB... ++ // ++ if( PtrBitmapBCB ) ++ { ++ CcUnpinData( PtrBitmapBCB ); ++ PtrBitmapBCB = NULL; ++ } ++ ++ } ++ ++ // ++ // Updating the Free Block count in the Group Descriptor... ++ // ++ ++ { ++ PBCB PtrDescriptorBCB = NULL; ++ PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; ++ // ++ // Updating the Free Blocks count in the Group Descriptor... ++ // ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount--; ++ ++ if( PtrVCB->LogBlockSize ) ++ { ++ // First block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize; ++ } ++ else ++ { ++ // Second block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize * 2; ++ } ++ NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); ++ NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); ++ ++ if (!CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrDescriptorBCB , ++ (PVOID*)&PtrGroupDescriptor )) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ // ++ // Ignore this error... ++ // Not fatal... ++ } ++ else ++ { ++ PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; ++ ++ // ++ // Not synchronously flushing this information... ++ // Lazy writing will do... ++ // ++ CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); ++ CcUnpinData( PtrDescriptorBCB ); ++ PtrDescriptorBCB = NULL; ++ } ++ } ++ ++ // ++ // Update the Block count ++ // in the super block and in the VCB ++ // ++ { ++ // Ext2 Super Block information... ++ PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; ++ PBCB PtrSuperBlockBCB = NULL; ++ ++ PtrVCB->FreeBlocksCount--; ++ ++ // Reading in the super block... ++ VolumeByteOffset.QuadPart = 1024; ++ NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrSuperBlockBCB, ++ (PVOID*)&PtrSuperBlock ) ) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ } ++ else ++ { ++ PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount; ++ CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); ++ if( PtrSuperBlockBCB ) ++ { ++ CcUnpinData( PtrSuperBlockBCB ); ++ PtrSuperBlockBCB = NULL; ++ } ++ } ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrBitmapBCB ) ++ { ++ CcUnpinData( PtrBitmapBCB ); ++ PtrBitmapBCB = NULL; ++ } ++ DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating a block - Block no : %ld", BlockNo ); ++ } ++ return BlockNo; ++} ++ ++/************************************************************************* ++* ++* Function: Ext2DeallocBlock() ++* ++* Description: ++* The functions will deallocate a data block ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: Success / Failure... ++* ++*************************************************************************/ ++BOOLEAN Ext2DeallocBlock( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2VCB PtrVCB, ++ ULONG BlockNo ) ++{ ++ // Buffer Control Block ++ PBCB PtrBitmapBCB = NULL; ++ BYTE * PtrBitmapBuffer = NULL; ++ BOOLEAN RC = TRUE; ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG LogicalBlockSize = 0; ++ // ULONG NumberOfBytesToRead = 0; ++ ++ DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating a block - Block no : %ld", BlockNo ); ++ ++ try ++ { ++ ULONG GroupNo; ++ ULONG BlockIndex; ++ ULONG BitmapIndex; ++ BYTE Bitmap; ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ GroupNo = BlockNo / PtrVCB->BlocksPerGroup; ++ BlockNo = BlockNo % PtrVCB->BlocksPerGroup; ++ ++ Bitmap = 1 << ( (BlockNo-1) % 8 ); ++ BitmapIndex = (BlockNo-1) / 8; ++ BlockIndex = BitmapIndex / LogicalBlockSize; ++ // Adjusting to index into the Logical block that contains the bitmap ++ BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize ); ++ ++ VolumeByteOffset.QuadPart = ++ ( PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock + BlockIndex ) ++ * LogicalBlockSize; ++ ++ // ++ // Read in the bitmap block... ++ // ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, // Can Wait... ++ &PtrBitmapBCB, ++ (PVOID*)&PtrBitmapBuffer ) ) ++ { ++ // Unable to Pin the data into the cache... ++ try_return (RC = FALSE); ++ } ++ ++ // ++ // Locate the block 'bit'... ++ // This block 'bit' is in the byte PtrBitmapBuffer[ BitmapIndex ] ++ if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0) ++ { ++ // This shouldn't have been so... ++ // The block was never allocated! ++ // How to deallocate something that hasn't been allocated? ++ // Hmmm... ;) ++ // Ignore this error... ++ try_return (RC = TRUE); ++ } ++ ++ // Setting the bit for the inode... ++ PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap); ++ ++ // Update the cache... ++ CcSetDirtyPinnedData( PtrBitmapBCB, NULL ); ++ ++ // Save up the BCB for forcing a synchronous write... ++ // Before completing the IRP... ++ Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject ); ++ ++ ++ if( PtrBitmapBCB ) ++ { ++ CcUnpinData( PtrBitmapBCB ); ++ PtrBitmapBCB = NULL; ++ } ++ ++ // ++ // Updating the Block count in the Group Descriptor... ++ // ++ ++ { ++ PBCB PtrDescriptorBCB = NULL; ++ PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; ++ ULONG NumberOfBytesToRead = 0; ++ // ++ // Updating the Free Blocks count in the Group Descriptor... ++ // ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount++; ++ ++ if( PtrVCB->LogBlockSize ) ++ { ++ // First block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize; ++ } ++ else ++ { ++ // Second block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize * 2; ++ } ++ NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); ++ NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); ++ ++ if (!CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrDescriptorBCB , ++ (PVOID*)&PtrGroupDescriptor )) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ // ++ // Ignore this error... ++ // Not fatal... ++ } ++ else ++ { ++ PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= ++ PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; ++ ++ // ++ // Not synchronously flushing this information... ++ // Lazy writing will do... ++ // ++ CcSetDirtyPinnedData( PtrDescriptorBCB, NULL ); ++ CcUnpinData( PtrDescriptorBCB ); ++ PtrDescriptorBCB = NULL; ++ } ++ } ++ ++ // ++ // Update the Block count ++ // in the super block and in the VCB ++ // ++ { ++ // Ext2 Super Block information... ++ PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; ++ PBCB PtrSuperBlockBCB = NULL; ++ ULONG NumberOfBytesToRead = 0; ++ ++ PtrVCB->FreeBlocksCount++; ++ ++ // Reading in the super block... ++ VolumeByteOffset.QuadPart = 1024; ++ NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrSuperBlockBCB, ++ (PVOID*)&PtrSuperBlock ) ) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ } ++ else ++ { ++ PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount; ++ CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); ++ Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); ++ CcUnpinData( PtrSuperBlockBCB ); ++ PtrSuperBlockBCB = NULL; ++ } ++ } ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ if( PtrBitmapBCB ) ++ { ++ CcUnpinData( PtrBitmapBCB ); ++ PtrBitmapBCB = NULL; ++ } ++ } ++ return RC; ++} ++ ++BOOLEAN Ext2UpdateFileSize( ++ PtrExt2IrpContext PtrIrpContext, ++ PFILE_OBJECT PtrFileObject, ++ PtrExt2FCB PtrFCB) ++{ ++ EXT2_INODE Inode; ++ PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; ++ ++ if( PtrFileObject->PrivateCacheMap ) ++ { ++ CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)); ++ } ++ // Now update the size on the disk... ++ // Read in the inode... ++ if( ! NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ return FALSE; ++ } ++ ++ Inode.i_size = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; ++ // Update time also??? ++ ++ // Updating the inode... ++ if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ return TRUE; ++ } ++ else ++ { ++ return FALSE; ++ } ++} ++ ++/************************************************************************* ++* ++* Function: Ext2DeleteFile() ++* ++* Description: ++* The functions will delete a file ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: Success / Failure... ++* ++*************************************************************************/ ++BOOLEAN Ext2DeleteFile( ++ PtrExt2FCB PtrFCB, ++ PtrExt2IrpContext PtrIrpContext) ++{ ++ EXT2_INODE Inode; ++ PtrExt2FCB PtrParentFCB = NULL; ++ PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; ++ ++ // ++ // Get the Parent Directory... ++ PtrParentFCB = Ext2LocateFCBInCore( PtrVCB, PtrFCB->ParentINodeNo ); ++ Ext2InitializeFCBInodeInfo( PtrFCB ); ++ ++ // 1. ++ // Free up the directory entry... ++ if( !Ext2FreeDirectoryEntry( PtrIrpContext, ++ PtrParentFCB, &PtrFCB->FCBName->ObjectName ) ) ++ { ++ return FALSE; ++ } ++ ++ // 2. ++ // Decrement Link count... ++ if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ return FALSE; ++ } ++ ++ ASSERT( Inode.i_links_count == PtrFCB->LinkCount ); ++ ++ Inode.i_links_count--; ++ PtrFCB->LinkCount = Inode.i_links_count; ++ ++ if( !Inode.i_links_count ) ++ { ++ // ++ // Setting the deletion time field in the inode... ++ // ++ ULONG Time; ++ Time = Ext2GetCurrentTime(); ++ Inode.i_dtime = Time ; ++ } ++ ++ // 3. ++ // Updating the inode... ++ ++ if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) ++ { ++ if( Inode.i_links_count ) ++ { ++ // Some more links to the same file are available... ++ // So we won't deallocate the data blocks... ++ return TRUE; ++ } ++ } ++ else ++ { ++ return FALSE; ++ } ++ ++ // 4. ++ // Free up the inode... ++ Ext2DeallocInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo ); ++ ++ // 5. ++ // Release the data blocks... ++ Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext); ++ ++ return TRUE; ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2ReleaseDataBlocks() ++* ++* Description: ++* The functions will release all the data blocks in a file ++* It does NOT update the file inode... ++* ++* Expected Interrupt Level (for execution) : ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: Success / Failure... ++* ++*************************************************************************/ ++BOOLEAN Ext2ReleaseDataBlocks( ++ PtrExt2FCB PtrFCB, ++ PtrExt2IrpContext PtrIrpContext) ++{ ++ PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; ++ ULONG LogicalBlockSize; ++ ULONG i; ++ ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ // Release the data blocks... ++ ++ // 1. ++ // Free up the triple indirect blocks... ++ if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ) ++ { ++ ++ PBCB PtrSIBCB = NULL; ++ PBCB PtrDIBCB = NULL; ++ PBCB PtrTIBCB = NULL; ++ ++ ULONG * PtrPinnedSIndirectBlock = NULL; ++ ULONG * PtrPinnedDIndirectBlock = NULL; ++ ULONG * PtrPinnedTIndirectBlock = NULL; ++ ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG TIndex, DIndex, SIndex; ++ ++ // Pin the Double Indirect Pointer Block... ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrTIBCB, ++ (PVOID*)&PtrPinnedTIndirectBlock )) ++ { ++ return FALSE; ++ } ++ ++ // Read the Block numbers off the Triple Indirect Pointer Block... ++ for( TIndex = 0; TIndex < (LogicalBlockSize/sizeof(ULONG)); TIndex++ ) ++ { ++ if( PtrPinnedTIndirectBlock[ TIndex ] ) ++ { ++ VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[TIndex] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrDIBCB, ++ (PVOID*)&PtrPinnedDIndirectBlock )) ++ { ++ return FALSE; ++ } ++ ++ // Read the Block numbers off the Double Indirect Pointer Blocks... ++ for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ ) ++ { ++ if( PtrPinnedDIndirectBlock[DIndex] ) ++ { ++ VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrSIBCB, ++ (PVOID*)&PtrPinnedSIndirectBlock )) ++ { ++ return FALSE; ++ } ++ ++ // Read the Block numbers off the Single Indirect Pointer Blocks and ++ // free the data blocks ++ for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ ) ++ { ++ if( PtrPinnedSIndirectBlock[ SIndex ] ) ++ { ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] ); ++ } ++ else ++ { ++ break; ++ } ++ } ++ CcUnpinData( PtrSIBCB ); ++ ++ // Deallocating ++ // Single Indirect Pointer Block ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] ); ++ } ++ else ++ { ++ break; ++ } ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++ CcUnpinData( PtrTIBCB ); ++ // Deallocating Triple Indirect Pointer Blocks ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ); ++ } ++ ++ // 2. ++ // Free up the double indirect blocks... ++ if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ) ++ { ++ PBCB PtrDIBCB = NULL; ++ PBCB PtrSIBCB = NULL; ++ ULONG * PtrPinnedSIndirectBlock = NULL; ++ ULONG * PtrPinnedDIndirectBlock = NULL; ++ ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG DIndex, SIndex; ++ ++ // Pin the Double Indirect Pointer Block... ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrDIBCB, ++ (PVOID*)&PtrPinnedDIndirectBlock )) ++ { ++ return FALSE; ++ } ++ ++ // Read the Block numbers off the Double Indirect Pointer Block... ++ for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ ) ++ { ++ if( PtrPinnedDIndirectBlock[DIndex] ) ++ { ++ VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrSIBCB, ++ (PVOID*)&PtrPinnedSIndirectBlock )) ++ { ++ return FALSE; ++ } ++ ++ // Read the Block numbers off the Single Indirect Pointer Blocks and ++ // free the data blocks ++ for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ ) ++ { ++ if( PtrPinnedSIndirectBlock[ SIndex ] ) ++ { ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] ); ++ } ++ else ++ { ++ break; ++ } ++ } ++ CcUnpinData( PtrSIBCB ); ++ ++ // Deallocating ++ // Single Indirect Pointer Block ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] ); ++ } ++ else ++ { ++ break; ++ } ++ } ++ CcUnpinData( PtrDIBCB ); ++ // Deallocating Double Indirect Pointer Blocks ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ); ++ } ++ ++ // 3. ++ // Free up the single indirect blocks... ++ if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) ++ { ++ PBCB PtrBCB = NULL; ++ ULONG * PtrPinnedSIndirectBlock = NULL; ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG Index; ++ ++ // Pin the Single Indirect Pointer Block... ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrBCB, ++ (PVOID*)&PtrPinnedSIndirectBlock )) ++ { ++ return FALSE; ++ } ++ ++ // Read the Block numbers off the Indirect Pointer Block and ++ // free the data blocks ++ for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); Index++ ) ++ { ++ if( PtrPinnedSIndirectBlock[Index] ) ++ { ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] ); ++ } ++ else ++ { ++ break; ++ } ++ } ++ CcUnpinData( PtrBCB ); ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] ); ++ } ++ ++ // 4. ++ // Free up the direct blocks... ++ for( i = 0; i < EXT2_NDIR_BLOCKS; i++ ) ++ { ++ if( PtrFCB->IBlock[ i ] ) ++ { ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] ); ++ } ++ else ++ { ++ break; ++ } ++ } ++ return TRUE; ++} ++ ++ ++BOOLEAN Ext2TruncateFileAllocationSize( ++ PtrExt2IrpContext PtrIrpContext, ++ PtrExt2FCB PtrFCB, ++ PFILE_OBJECT PtrFileObject, ++ PLARGE_INTEGER PtrAllocationSize ) ++{ ++ PtrExt2VCB PtrVCB = PtrFCB->PtrVCB; ++ ULONG LogicalBlockSize; ++ ULONG i; ++ ++ ULONG NoOfBlocksToBeLeft= 0; ++ ULONG CurrentBlockNo = 0; ++ ++ // ++ // This function has not been tested... ++ // ++ Ext2BreakPoint(); ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ NoOfBlocksToBeLeft = (ULONG) (PtrAllocationSize->QuadPart / LogicalBlockSize); ++ ++ ++ ++ // Release the data blocks... ++ ++ // 1. ++ // Free up the direct blocks... ++ for( i = NoOfBlocksToBeLeft; i < EXT2_NDIR_BLOCKS; i++ ) ++ { ++ if( PtrFCB->IBlock[ i ] ) ++ { ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] ); ++ PtrFCB->IBlock[ i ] = 0; ++ } ++ else ++ { ++ break; ++ } ++ } ++ ++ // 2. ++ // Free up the single indirect blocks... ++ CurrentBlockNo = EXT2_NDIR_BLOCKS; ++ ++ if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] ) ++ { ++ PBCB PtrBCB = NULL; ++ ULONG * PtrPinnedSIndirectBlock = NULL; ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG Index; ++ ++ // Pin the Single Indirect Pointer Block... ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ TRUE, ++ &PtrBCB, ++ (PVOID*)&PtrPinnedSIndirectBlock )) ++ { ++ return FALSE; ++ } ++ ++ // Read the Block numbers off the Indirect Pointer Block and ++ // free the data blocks ++ for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); ++ Index++, CurrentBlockNo++ ) ++ { ++ if( CurrentBlockNo >= NoOfBlocksToBeLeft ) ++ { ++ if( PtrPinnedSIndirectBlock[Index] ) ++ { ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] ); ++ } ++ else ++ { ++ break; ++ } ++ } ++ else if( !PtrPinnedSIndirectBlock[Index] ) ++ { ++ break; ++ } ++ } ++ if( NoOfBlocksToBeLeft <= EXT2_NDIR_BLOCKS ) ++ { ++ Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] ); ++ PtrFCB->IBlock[ EXT2_IND_BLOCK ] = 0; ++ } ++ ++ CcUnpinData( PtrBCB ); ++ } ++ ++ // 3. ++ // Free up the double indirect blocks... ++ if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] ) ++ { ++ ++ } ++ ++ // 4. ++ // Free up the triple indirect blocks... ++ if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ) ++ { ++ ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN Ext2IsDirectoryEmpty( ++ PtrExt2FCB PtrFCB, ++ PtrExt2CCB PtrCCB, ++ PtrExt2IrpContext PtrIrpContext) ++{ ++ ++ PFILE_OBJECT PtrFileObject = NULL; ++ ++ if( !Ext2IsFlagOn(PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY) ) ++ { ++ return FALSE; ++ } ++ ++ // 1. ++ // Initialize the Blocks in the FCB... ++ // ++ Ext2InitializeFCBInodeInfo( PtrFCB ); ++ ++ ++ // 2. ++ // Get hold of the file object... ++ // ++ PtrFileObject = PtrCCB->PtrFileObject; ++ ++ ++ // 3. ++ // Now initiating Caching, pinned access to be precise ... ++ // ++ if (PtrFileObject->PrivateCacheMap == NULL) ++ { ++ CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), ++ TRUE, // We utilize pin access for directories ++ &(Ext2GlobalData.CacheMgrCallBacks), // callbacks ++ PtrFCB ); // The context used in callbacks ++ } ++ ++ // 4. ++ // Getting down to the real business now... ;) ++ // Read in the directory contents and do a search ++ // ++ { ++ LARGE_INTEGER StartBufferOffset; ++ ULONG PinBufferLength; ++ ULONG BufferIndex; ++ PBCB PtrBCB = NULL; ++ BYTE * PtrPinnedBlockBuffer = NULL; ++ PEXT2_DIR_ENTRY PtrDirEntry = NULL; ++ BOOLEAN Found = FALSE; ++ int i; ++ ++ ++ ++ StartBufferOffset.QuadPart = 0; ++ ++ // ++ // Read in the whole directory ++ // **Bad programming** ++ // Will do for now. ++ // ++ PinBufferLength = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; ++ if (!CcMapData( PtrFileObject, ++ &StartBufferOffset, ++ PinBufferLength, ++ TRUE, ++ &PtrBCB, ++ (PVOID*)&PtrPinnedBlockBuffer ) ) ++ { ++ return FALSE; ++ } ++ ++ // ++ // Walking through now... ++ // ++ for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) ++ { ++ PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; ++ if( PtrDirEntry->inode == 0) ++ { ++ // Deleted entry... ++ // Ignore... ++ continue; ++ } ++ if( PtrDirEntry->name[0] == '.' ) ++ { ++ if( PtrDirEntry->name_len == 1 || ++ ( PtrDirEntry->name_len == 2 && PtrDirEntry->name[1] == '.' ) ) ++ { ++ continue; ++ } ++ } ++ Found = TRUE; ++ } ++ CcUnpinData( PtrBCB ); ++ PtrBCB = NULL; ++ ++ return !Found; ++ } ++} ++ ++ ++NTSTATUS Ext2RenameOrLinkFile( ++ PtrExt2FCB PtrSourceFCB, ++ PFILE_OBJECT PtrSourceFileObject, ++ PtrExt2IrpContext PtrIrpContext, ++ PIRP PtrIrp, ++ PFILE_RENAME_INFORMATION PtrRenameInfo) ++{ ++ PtrExt2FCB PtrParentFCB = NULL; ++ PtrExt2VCB PtrSourceVCB = PtrSourceFCB->PtrVCB; ++ ++ PtrExt2FCB PtrTargetFCB = NULL; ++ PtrExt2CCB PtrTargetCCB = NULL; ++ PtrExt2VCB PtrTargetVCB = NULL; ++ ++ ++ FILE_INFORMATION_CLASS FunctionalityRequested; ++ PIO_STACK_LOCATION PtrIoStackLocation = NULL; ++ PFILE_OBJECT TargetFileObject = NULL; ++ BOOLEAN ReplaceExistingFile = FALSE; ++ BOOLEAN Found = FALSE; ++ ++ PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ++ FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass; ++ TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject; ++ ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists; ++ ++ // Get the FCB and CCB pointers ++ Ext2GetFCB_CCB_VCB_FromFileObject ( ++ TargetFileObject , &PtrTargetFCB, &PtrTargetCCB, &PtrTargetVCB); ++ ++ if( !PtrTargetCCB ) ++ { ++ return STATUS_ACCESS_DENIED; ++ } ++ if( PtrTargetVCB != PtrSourceVCB ) ++ { ++ // Cannot rename across volumes... ++ return STATUS_ACCESS_DENIED; ++ } ++ if ( !Ext2IsFlagOn( PtrTargetFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) ++ { ++ // Target has to be a folder... ++ return STATUS_ACCESS_DENIED; ++ } ++ ++ // 1. ++ // Open the parent folder... ++ PtrParentFCB = Ext2LocateFCBInCore( PtrSourceVCB, PtrSourceFCB->ParentINodeNo ); ++ if( !PtrParentFCB ) ++ { ++ // Get the folder from the disk ++ // Use the inode no PtrSourceFCB->ParentINodeNo ++ // ++ // For now... ++ return STATUS_ACCESS_DENIED; ++ } ++ ++ // 2. ++ // Check if the file exists in the TargetFolder... ++ { ++ LARGE_INTEGER StartBufferOffset; ++ ULONG PinBufferLength; ++ ULONG BufferIndex; ++ PBCB PtrBCB = NULL; ++ BYTE * PtrPinnedBlockBuffer = NULL; ++ PEXT2_DIR_ENTRY PtrDirEntry = NULL; ++ int i; ++ ++ StartBufferOffset.QuadPart = 0; ++ ++ // ++ // Read in the whole directory ++ // ++ if ( TargetFileObject->PrivateCacheMap == NULL ) ++ { ++ CcInitializeCacheMap( ++ TargetFileObject, ++ (PCC_FILE_SIZES)(&(PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), ++ TRUE, // We utilize pin access for directories ++ &(Ext2GlobalData.CacheMgrCallBacks), // callbacks ++ PtrTargetCCB ); // The context used in callbacks ++ } ++ ++ PinBufferLength = PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart; ++ if (!CcMapData( TargetFileObject, ++ &StartBufferOffset, ++ PinBufferLength, ++ TRUE, ++ &PtrBCB, ++ (PVOID*)&PtrPinnedBlockBuffer ) ) ++ { ++ return FALSE; ++ } ++ ++ // ++ // Walking through now... ++ // ++ for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len ) ++ { ++ PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ]; ++ if( PtrDirEntry->inode == 0) ++ { ++ // Deleted entry... ++ // Ignore... ++ continue; ++ } ++ if( PtrDirEntry->name_len == (PtrTargetCCB->RenameLinkTargetFileName.Length/2) ) ++ { ++ Found = TRUE; ++ for( i =0; i < PtrDirEntry->name_len ; i++ ) ++ { ++ if( PtrDirEntry->name[i] != PtrTargetCCB->RenameLinkTargetFileName.Buffer[i] ) ++ { ++ Found = FALSE; ++ break; ++ } ++ } ++ } ++ } ++ CcUnpinData( PtrBCB ); ++ PtrBCB = NULL; ++ } ++ ++ // 3. ++ // If the file exists, delete it if requested.. ++ if( Found ) ++ { ++ if( !ReplaceExistingFile ) ++ { ++ return STATUS_OBJECT_NAME_COLLISION; ++ } ++ // Delete the file... ++ // Reject this for now... ++ return STATUS_ACCESS_DENIED; ++ } ++ ++ ++ { ++ ULONG Type = EXT2_FT_REG_FILE; ++ if( Ext2IsFlagOn( PtrSourceFCB->FCBFlags, EXT2_FCB_DIRECTORY ) ) ++ { ++ Type = EXT2_FT_DIR; ++ } ++ ++ ASSERT( TargetFileObject ); ++ ++ // 4. ++ // Remove the old entry... ++ Ext2FreeDirectoryEntry( PtrIrpContext, PtrParentFCB, ++ &PtrSourceFCB->FCBName->ObjectName); ++ ++ // 5. ++ // Create a new entry... ++ Ext2MakeNewDirectoryEntry( ++ PtrIrpContext, // This IRP Context ++ PtrTargetFCB, // Parent Folder FCB ++ TargetFileObject, // Parent Folder Object ++ &PtrTargetCCB->RenameLinkTargetFileName, // New entry's name ++ Type, // The type of the new entry ++ PtrSourceFCB->INodeNo ); // The inode no of the new entry... ++ ++ } ++ ++ // 6. ++ // Update the PtrSourceFCB... ++ { ++ ++ PtrExt2ObjectName PtrObjectName; ++ if( PtrSourceFCB->FCBName ) ++ { ++ Ext2ReleaseObjectName( PtrSourceFCB->FCBName ); ++ } ++ PtrObjectName = Ext2AllocateObjectName(); ++ Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &PtrTargetCCB->RenameLinkTargetFileName ); ++ PtrSourceFCB->FCBName = PtrObjectName; ++ PtrSourceFCB->ParentINodeNo = PtrTargetFCB->INodeNo; ++ } ++ ++ if( PtrTargetCCB->RenameLinkTargetFileName.Length ) ++ { ++ Ext2DeallocateUnicodeString( &PtrTargetCCB->RenameLinkTargetFileName ); ++ } ++ ++ return STATUS_SUCCESS; ++} diff --cc reactos/drivers/filesystems/ext2/src/misc.c index 00000000000,fd9c98099f0..fd9c98099f0 mode 000000,100644..100644 --- a/reactos/drivers/filesystems/ext2/src/misc.c +++ b/reactos/drivers/filesystems/ext2/src/misc.c diff --cc reactos/drivers/filesystems/ext2/src/read.c index 00000000000,e4b47de045c..e4b47de045c mode 000000,100644..100644 --- a/reactos/drivers/filesystems/ext2/src/read.c +++ b/reactos/drivers/filesystems/ext2/src/read.c diff --cc reactos/drivers/filesystems/ext2/src/shutdown.c index 00000000000,00000000000..0ec7d2f36b8 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/shutdown.c @@@ -1,0 -1,0 +1,211 @@@ ++/************************************************************************* ++* ++* File: shutdown.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains code to handle the "shutdown notification" dispatch entry point. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_SHUTDOWN ++#define DEBUG_LEVEL (DEBUG_TRACE_SHUTDOWN) ++ ++ ++/************************************************************************* ++* ++* Function: Ext2Shutdown() ++* ++* Description: ++* All disk-based FSDs can expect to receive this shutdown notification ++* request whenever the system is about to be halted gracefully. If you ++* design and implement a network redirector, you must register explicitly ++* for shutdown notification by invoking the IoRegisterShutdownNotification() ++* routine from your driver entry. ++* ++* Note that drivers that register to receive shutdown notification get ++* invoked BEFORE disk-based FSDs are told about the shutdown notification. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: Irrelevant. ++* ++*************************************************************************/ ++NTSTATUS Ext2Shutdown( ++ PDEVICE_OBJECT DeviceObject, // the logical volume device object ++ PIRP Irp) // I/O Request Packet ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ BOOLEAN AreWeTopLevel = FALSE; ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Shutdown IRP received...", 0); ++ ++ FsRtlEnterFileSystem(); ++ ASSERT(DeviceObject); ++ ASSERT(Irp); ++ ++ // set the top level context ++ AreWeTopLevel = Ext2IsIrpTopLevel(Irp); ++ ++ try ++ { ++ ++ // get an IRP context structure and issue the request ++ PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); ++ ASSERT(PtrIrpContext); ++ ++ RC = Ext2CommonShutdown(PtrIrpContext, Irp); ++ ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ ++ RC = Ext2ExceptionHandler(PtrIrpContext, Irp); ++ ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ if (AreWeTopLevel) ++ { ++ IoSetTopLevelIrp(NULL); ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2CommonShutdown() ++* ++* Description: ++* The actual work is performed here. Basically, all we do here is ++* internally invoke a flush on all mounted logical volumes. This, in ++* tuen, will result in all open file streams being flushed to disk. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: Irrelevant ++* ++*************************************************************************/ ++NTSTATUS Ext2CommonShutdown( ++PtrExt2IrpContext PtrIrpContext, ++PIRP PtrIrp) ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PIO_STACK_LOCATION PtrIoStackLocation = NULL; ++ IO_STATUS_BLOCK LocalIoStatus; ++ ++ try ++ { ++ // First, get a pointer to the current I/O stack location ++ PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ++ ASSERT(PtrIoStackLocation); ++ ++ // (a) Block all new "mount volume" requests by acquiring an appropriate ++ // global resource/lock. ++ // (b) Go through your linked list of mounted logical volumes and for ++ // each such volume, do the following: ++ // (i) acquire the volume resource exclusively ++ // (ii) invoke Ext2FlushLogicalVolume() (internally) to flush the ++ // open data streams belonging to the volume from the system ++ // cache ++ // (iii) Invoke the physical/virtual/logical target device object ++ // on which the volume is mounted and inform this device ++ // about the shutdown request (Use IoBuildSynchronousFsdRequest() ++ // to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you ++ // will then issue to the target device object). ++ // (iv) Wait for the completion of the shutdown processing by the target ++ // device object ++ // (v) Release the VCB resource you will have acquired in (i) above. ++ ++ // Once you have processed all the mounted logical volumes, you can release ++ // all acquired global resources and leave (in peace :-) ++ ++ ++ ++/*//////////////////////////////////////////// ++ // ++ // Update the Group... ++ // ++ if( PtrVCB->LogBlockSize ) ++ { ++ // First block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize; ++ } ++ else ++ { ++ // Second block contains the descriptors... ++ VolumeByteOffset.QuadPart = LogicalBlockSize * 2; ++ } ++ ++ NumberOfBytesToRead = sizeof( struct ext2_group_desc ); ++ NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); ++ ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrBCB, ++ &PtrCacheBuffer )) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); ++ } ++ else ++ { ++ // ++ // Saving up Often Used Group Descriptor Information in the VCB... ++ // ++ unsigned int DescIndex ; ++ ++ DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); ++ PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer; ++ for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ ) ++ { ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock ++ = PtrGroupDescriptor[ DescIndex ].bg_inode_table; ++ ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock ++ = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap ++ ; ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock ++ = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap ++ ; ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount ++ = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count; ++ ++ PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount ++ = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count; ++ } ++ CcUnpinData( PtrBCB ); ++ PtrBCB = NULL; ++ } ++*///////////////////////////////////////////// ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ ++ // See the read/write examples for how to fill in this portion ++ ++ } // end of "finally" processing ++ ++ return(RC); ++} diff --cc reactos/drivers/filesystems/ext2/src/volinfo.c index 00000000000,00000000000..2e341626e03 new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/volinfo.c @@@ -1,0 -1,0 +1,339 @@@ ++/************************************************************************* ++* ++* File: volinfo.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains code to handle the various Volume Information related calls. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++ ++ ++#include "ext2fsd.h" ++ ++ ++ ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_VOL_INFORMATION ++#define DEBUG_LEVEL (DEBUG_TRACE_VOLINFO) ++ ++ ++/************************************************************************* ++* ++* Function: Ext2QueryVolInfo() ++* ++* Description: ++* The I/O Manager will invoke this routine to handle a ++* Query Volume Info IRP ++* ++* Expected Interrupt Level (for execution) : ++* ++* ??? ++* ++* Arguments: ++* ++* DeviceObject - Supplies the volume device object where the ++* file exists ++* ++* Irp - Supplies the Irp being processed ++* ++* ++* Return Value: ++* ++* NTSTATUS - The FSD status for the IRP ++* ++*************************************************************************/ ++NTSTATUS Ext2QueryVolInfo ( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp) ++{ ++ ++ // The Return Status ++ NTSTATUS Status = STATUS_SUCCESS; ++ ++ // The IRP Stack Location ++ PIO_STACK_LOCATION IrpSp = NULL; ++ ++ // Volume Control Block ++ PtrExt2VCB PtrVCB = NULL; ++ ++ // The class of the query IRP ++ FS_INFORMATION_CLASS FsInformationClass; ++ ++ // The System Buffer Pointer ++ PVOID Buffer = NULL; ++ ++ // Parameter Length ++ ULONG Length = 0; ++ ++ // Bytes copied... ++ ULONG BytesCopied = 0; ++ ++ // Pointers to the Output Information... ++ PFILE_FS_VOLUME_INFORMATION PtrVolumeInformation = NULL; ++ PFILE_FS_SIZE_INFORMATION PtrSizeInformation = NULL; ++ PFILE_FS_ATTRIBUTE_INFORMATION PtrAttributeInformation = NULL; ++ PFILE_FS_DEVICE_INFORMATION PtrDeviceInformation = NULL; ++ PFILE_FS_FULL_SIZE_INFORMATION PtrFullSizeInformation = NULL; ++ ++ ++ // Now for the handler code... ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "QueryVolumeInformation IRP", 0); ++ ++ FsRtlEnterFileSystem(); ++ ++ try ++ { ++ // Getting a pointer to the current I/O stack location ++ IrpSp = IoGetCurrentIrpStackLocation(Irp); ++ ASSERT( IrpSp ); ++ ++ // Getting the VCB and Verifying it... ++ PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension ); ++ ASSERT(PtrVCB); ++ ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB); ++ ++ // Getting the query parameters... ++ Length = IrpSp->Parameters.QueryVolume.Length; ++ FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass; ++ Buffer = Irp->AssociatedIrp.SystemBuffer; ++ ++ // Now servicing the request depending on the type... ++ switch (FsInformationClass) ++ { ++ case FileFsVolumeInformation: ++ DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsVolumeInformation", 0); ++ PtrVolumeInformation = Buffer; ++ PtrVolumeInformation->SupportsObjects = FALSE; ++ PtrVolumeInformation->VolumeCreationTime.QuadPart = 0; ++ RtlCopyMemory( ++ PtrVolumeInformation->VolumeLabel, // destination ++ PtrVCB->PtrVPB->VolumeLabel, // source ++ PtrVCB->PtrVPB->VolumeLabelLength ); ++ PtrVolumeInformation->VolumeLabelLength = PtrVCB->PtrVPB->VolumeLabelLength; ++ PtrVolumeInformation->VolumeSerialNumber = PtrVCB->PtrVPB->SerialNumber; ++ BytesCopied = sizeof( FILE_FS_VOLUME_INFORMATION ) + PtrVolumeInformation->VolumeLabelLength - sizeof( WCHAR); ++ break; ++ ++ case FileFsSizeInformation: ++ DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsSizeInformation", 0); ++ PtrSizeInformation = Buffer; ++ PtrSizeInformation->BytesPerSector = DeviceObject->SectorSize; ++ PtrSizeInformation->AvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount; ++ PtrSizeInformation->SectorsPerAllocationUnit = ( EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize; ++ PtrSizeInformation->TotalAllocationUnits.QuadPart = PtrVCB->BlocksCount; ++ BytesCopied = sizeof( FILE_FS_SIZE_INFORMATION ); ++ break; ++ ++ case FileFsDeviceInformation: ++ DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsDeviceInformation", 0); ++ PtrDeviceInformation = Buffer; ++ PtrDeviceInformation->DeviceType = FILE_DEVICE_DISK; ++ PtrDeviceInformation->Characteristics = FILE_DEVICE_IS_MOUNTED; ++ BytesCopied = sizeof( FILE_FS_DEVICE_INFORMATION ); ++ break; ++ ++ case FileFsAttributeInformation: ++ DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsAttributeInformation", 0); ++ PtrAttributeInformation = Buffer; ++ RtlCopyMemory( PtrAttributeInformation->FileSystemName, L"EXT2", 10 ); ++ PtrAttributeInformation->FileSystemNameLength = 8; ++ PtrAttributeInformation->MaximumComponentNameLength = 255; ++ PtrAttributeInformation->FileSystemAttributes = ++ FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; ++ BytesCopied = sizeof( FILE_FS_ATTRIBUTE_INFORMATION ) + 8; ++ ++ break; ++ ++ case FileFsFullSizeInformation: ++ DebugTrace(DEBUG_TRACE_MISC, "Query Volume - FileFsFullSizeInformation", 0); ++ PtrFullSizeInformation = Buffer; ++ PtrFullSizeInformation->BytesPerSector = DeviceObject->SectorSize; ++ PtrFullSizeInformation->ActualAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount; ++ PtrFullSizeInformation->SectorsPerAllocationUnit = (EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize; ++ PtrFullSizeInformation->TotalAllocationUnits.QuadPart = PtrVCB->BlocksCount; ++ PtrFullSizeInformation->CallerAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount - PtrVCB->ReservedBlocksCount; ++ BytesCopied = sizeof( FILE_FS_FULL_SIZE_INFORMATION ); ++ break; ++ ++ default: ++ Status = STATUS_INVALID_PARAMETER; ++ DebugTrace(DEBUG_TRACE_MISC, "Query Volume - STATUS_INVALID_PARAMETER", 0); ++ break; ++ } ++ ++ if( IrpSp->Parameters.QueryVolume.Length < BytesCopied ) ++ { ++ BytesCopied = IrpSp->Parameters.QueryVolume.Length; ++ Status = STATUS_BUFFER_OVERFLOW; ++ DebugTrace(DEBUG_TRACE_MISC, " === Buffer insufficient", 0); ++ } ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ Irp->IoStatus.Information = BytesCopied; ++ Ext2CompleteRequest( Irp, Status ); ++ } ++ FsRtlExitFileSystem(); ++ ++ // ++ // Now return to the caller ++ // ++ ++ return Status; ++} ++ ++ ++ ++NTSTATUS Ext2SetVolInfo( ++ IN PDEVICE_OBJECT DeviceObject, ++ IN PIRP Irp) ++{ ++ // The Return Status ++ NTSTATUS Status = STATUS_SUCCESS; ++ ++ // The IRP Stack Location ++ PIO_STACK_LOCATION IrpSp = NULL; ++ ++ // Volume Control Block ++ PtrExt2VCB PtrVCB = NULL; ++ ++ // The class of the query IRP ++ FS_INFORMATION_CLASS FsInformationClass; ++ ++ // Pointers to the Output Information... ++ PFILE_FS_LABEL_INFORMATION PtrVolumeLabelInformation = NULL; ++ ++ // Now for the handler code... ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Set Volume Information IRP", 0); ++ ++ FsRtlEnterFileSystem(); ++ ++ try ++ { ++ // Getting a pointer to the current I/O stack location ++ IrpSp = IoGetCurrentIrpStackLocation(Irp); ++ ASSERT( IrpSp ); ++ ++ // Getting the VCB and Verifying it... ++ PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension ); ++ AssertVCB(PtrVCB); ++ ++ // Getting the query parameters... ++ // Length = IrpSp->Parameters.SetVolume.Length; ++#ifdef _GNU_NTIFS_ ++ FsInformationClass = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.SetVolume.FsInformationClass; ++#else ++ FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass; ++#endif ++ ++ // Now servicing the request depending on the type... ++ switch (FsInformationClass) ++ { ++ case FileFsLabelInformation: ++ PtrVolumeLabelInformation = Irp->AssociatedIrp.SystemBuffer; ++ if( PtrVolumeLabelInformation->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH || // This is the maximum that the ++ // VPB can take... ++ PtrVolumeLabelInformation->VolumeLabelLength > 32 ) // this is the maximum that Ext2 FS can support.. ++ { ++ try_return( Status = STATUS_INVALID_VOLUME_LABEL ); ++ } ++ ++ PtrVCB->PtrVPB->VolumeLabelLength = (USHORT)PtrVolumeLabelInformation->VolumeLabelLength ; ++ RtlCopyMemory( ++ PtrVCB->PtrVPB->VolumeLabel, // destination ++ PtrVolumeLabelInformation->VolumeLabel, // source ++ PtrVolumeLabelInformation->VolumeLabelLength ); ++ ++ { ++ // Now update the volume's super block... ++ ++ PEXT2_SUPER_BLOCK PtrSuperBlock = NULL; ++ PBCB PtrSuperBlockBCB = NULL; ++ LARGE_INTEGER VolumeByteOffset; ++ ULONG LogicalBlockSize = 0; ++ ULONG NumberOfBytesToRead = 0; ++ ++ ++ // Reading in the super block... ++ VolumeByteOffset.QuadPart = 1024; ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ // THis shouldn't be more than a block in size... ++ NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize ); ++ ++ if( !CcPinRead( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ NumberOfBytesToRead, ++ TRUE, ++ &PtrSuperBlockBCB, ++ (PVOID*)&PtrSuperBlock ) ) ++ { ++ DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); ++ try_return( Status = STATUS_INVALID_VOLUME_LABEL ); ++ } ++ else ++ { ++ ULONG i; ++ for( i = 0; i < (PtrVolumeLabelInformation->VolumeLabelLength/2) ; i++ ) ++ { ++ PtrSuperBlock->s_volume_name[i] = ++ (char) PtrVolumeLabelInformation->VolumeLabel[i] ; ++ if( PtrSuperBlock->s_volume_name[i] == 0 ) ++ { ++ break; ++ } ++ } ++ if( i < 16 ) ++ { ++ PtrSuperBlock->s_volume_name[i] = 0; ++ } ++ ++ ++ CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL ); ++ ++ // Not saving and flushing this information synchronously... ++ // This is not a critical information.. ++ // Settling for lazy writing of this information ++ ++ // Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject ); ++ ++ if( PtrSuperBlockBCB ) ++ { ++ CcUnpinData( PtrSuperBlockBCB ); ++ PtrSuperBlockBCB = NULL; ++ } ++ ++ } ++ } ++ ++ break; ++ default: ++ Status = STATUS_INVALID_PARAMETER; ++ DebugTrace(DEBUG_TRACE_MISC, "Query Volume - STATUS_INVALID_PARAMETER", 0); ++ break; ++ } ++ ++ try_exit: NOTHING; ++ } ++ finally ++ { ++ Irp->IoStatus.Information = 0; ++ Ext2CompleteRequest( Irp, Status ); ++ } ++ FsRtlExitFileSystem(); ++ ++ // ++ // Now return to the caller ++ // ++ ++ return Status; ++} diff --cc reactos/drivers/filesystems/ext2/src/write.c index 00000000000,00000000000..1596ecd95eb new file mode 100644 --- /dev/null +++ b/reactos/drivers/filesystems/ext2/src/write.c @@@ -1,0 -1,0 +1,1483 @@@ ++/************************************************************************* ++* ++* File: write.c ++* ++* Module: Ext2 File System Driver (Kernel mode execution only) ++* ++* Description: ++* Contains code to handle the "Write" dispatch entry point. ++* ++* Author: Manoj Paul Joseph ++* ++* ++*************************************************************************/ ++ ++#include "ext2fsd.h" ++ ++// define the file specific bug-check id ++#define EXT2_BUG_CHECK_ID EXT2_FILE_WRITE ++ ++#define DEBUG_LEVEL (DEBUG_TRACE_WRITE) ++ ++ ++/************************************************************************* ++* ++* Function: Ext2Write() ++* ++* Description: ++* The I/O Manager will invoke this routine to handle a write ++* request ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution ++* to be deferred to a worker thread context) ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2Write( ++PDEVICE_OBJECT DeviceObject, // the logical volume device object ++PIRP Irp) // I/O Request Packet ++{ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PtrExt2IrpContext PtrIrpContext = NULL; ++ BOOLEAN AreWeTopLevel = FALSE; ++ ++ DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Write IRP Received...", 0); ++ ++ // Ext2BreakPoint(); ++ ++ FsRtlEnterFileSystem(); ++ ASSERT(DeviceObject); ++ ASSERT(Irp); ++ ++ // set the top level context ++ AreWeTopLevel = Ext2IsIrpTopLevel(Irp); ++ ++ try ++ { ++ // get an IRP context structure and issue the request ++ PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject); ++ ASSERT(PtrIrpContext); ++ ++ RC = Ext2CommonWrite(PtrIrpContext, Irp); ++ } ++ except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) ++ { ++ RC = Ext2ExceptionHandler(PtrIrpContext, Irp); ++ Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); ++ } ++ ++ if (AreWeTopLevel) ++ { ++ IoSetTopLevelIrp(NULL); ++ } ++ ++ FsRtlExitFileSystem(); ++ ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2CommonWrite() ++* ++* Description: ++* The actual work is performed here. This routine may be invoked in one' ++* of the two possible contexts: ++* (a) in the context of a system worker thread ++* (b) in the context of the original caller ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: STATUS_SUCCESS/Error ++* ++*************************************************************************/ ++NTSTATUS Ext2CommonWrite( ++ PtrExt2IrpContext PtrIrpContext, ++ PIRP PtrIrp) ++{ ++ ++ NTSTATUS RC = STATUS_SUCCESS; ++ PIO_STACK_LOCATION PtrIoStackLocation = NULL; ++ LARGE_INTEGER ByteOffset; ++ uint32 WriteLength = 0; ++ uint32 NumberBytesWritten = 0; ++ PFILE_OBJECT PtrFileObject = NULL; ++ PtrExt2FCB PtrFCB = NULL; ++ PtrExt2CCB PtrCCB = NULL; ++ PtrExt2VCB PtrVCB = NULL; ++ PtrExt2NTRequiredFCB PtrReqdFCB = NULL; ++ PERESOURCE PtrResourceAcquired = NULL; ++ IO_STATUS_BLOCK LocalIoStatus; ++ void *PtrSystemBuffer = NULL; ++ uint32 KeyValue = 0; ++ ++ BOOLEAN CompleteIrp = TRUE; ++ BOOLEAN PostRequest = FALSE; ++ ++ BOOLEAN CanWait = FALSE; ++ BOOLEAN PagingIo = FALSE; ++ BOOLEAN NonBufferedIo = FALSE; ++ BOOLEAN SynchronousIo = FALSE; ++ BOOLEAN IsThisADeferredWrite = FALSE; ++ BOOLEAN WritingAtEndOfFile = FALSE; ++ ++ EXT2_IO_RUN *PtrIoRuns = NULL; ++ ++ PBCB PtrPinnedSIndirectBCB = NULL; ++ PBCB PtrPinnedDIndirectBCB = NULL; ++ PBCB PtrPinnedTIndirectBCB = NULL; ++ ++ // Used to cache the Single Indirect blocks pointed to by ++ // the Double Indirect block ++ PEXT2_SIBLOCKS PtrDIArray = NULL; ++ ULONG DIArrayCount = 0; ++ ++ // Used to cache the Single Indirect blocks pointed to by ++ // the Triple Indirect block ++ PEXT2_SIBLOCKS PtrTIArray = NULL; ++ ULONG TIArrayCount = 0; ++ ++ ++ try ++ { ++ // First, get a pointer to the current I/O stack location ++ PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ++ ASSERT(PtrIoStackLocation); ++ ++ PtrFileObject = PtrIoStackLocation->FileObject; ++ ASSERT(PtrFileObject); ++ ++ // If this happens to be a MDL write complete request, then ++ // allocated MDL can be freed. ++ if(PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE) ++ { ++ // Caller wants to tell the Cache Manager that a previously ++ // allocated MDL can be freed. ++ Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, FALSE); ++ // The IRP has been completed. ++ CompleteIrp = FALSE; ++ try_return(RC = STATUS_SUCCESS); ++ } ++ ++ // If this is a request at IRQL DISPATCH_LEVEL, then post the request ++ if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ try_return(RC = STATUS_PENDING); ++ } ++ ++ ++ // Get the FCB and CCB pointers ++ Ext2GetFCB_CCB_VCB_FromFileObject ( ++ PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); ++ ++ ++ // Get some of the parameters supplied to us ++ ByteOffset = PtrIoStackLocation->Parameters.Write.ByteOffset; ++ WriteLength = PtrIoStackLocation->Parameters.Write.Length; ++ ++ CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); ++ PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE); ++ NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE); ++ SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE); ++ ++ if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_NAME, " === Write File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_FILE_NAME, " === Write File Name : -null-", 0); ++ } ++ ++ DebugTrace( DEBUG_TRACE_SPECIAL, " ->ByteCount = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length); ++ DebugTrace( DEBUG_TRACE_SPECIAL, " ->ByteOffset.LowPart = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart); ++ ++ if( CanWait ) ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Can Wait ", 0 ); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Can't Wait ", 0 ); ++ } ++ ++ if( PagingIo ) ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Paging Io ", 0 ); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Not Paging Io", 0 ); ++ } ++ ++ if( SynchronousIo ) ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->SynchronousIo ", 0 ); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->ASynchronousIo ", 0 ); ++ } ++ ++ if( NonBufferedIo ) ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->NonBufferedIo", 0 ); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->BufferedIo", 0 ); ++ } ++ // Check at this point whether the file object being ++ // used for write really did have write permission requested when the ++ // create/open operation was performed. ++ // Don't do this for paging io... ++ ++ if (WriteLength == 0) ++ { ++ // a 0 byte write can be immediately succeeded ++ try_return(RC); ++ } ++ ++ // Is this a write of the volume itself ? ++ if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) ++ { ++ // ++ // >>>>>>>>>>>>>>>>>> VOLUME WRITE <<<<<<<<<<<<<< ++ // ++ ++ // Validate the offset and length first... ++ // ....................................... ++ ++ // Acquire the volume resource exclusively ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Write]", PtrFileObject); ++ } ++ ++ if( PagingIo ) ++ { ++ // This is Paging IO... ++ ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCBPaging Exclusively [Write]", 0); ++ DebugTraceState( "VCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [Write]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters ); ++ ++ if( !ExAcquireResourceExclusiveLite( &( PtrVCB->PagingIoResource ), FALSE ) ) ++ { ++ // post the request to be processed in the context of a worker thread ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCBPaging Acquisition FAILED [Write]", 0); ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ try_return(RC = STATUS_PENDING); ++ } ++ ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCBPaging Acquired [Write]", 0); ++ PtrResourceAcquired = &(PtrVCB->PagingIoResource); ++ } ++ else ++ { ++ // This is not Paging IO... ++ ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Write]", 0); ++ DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Write]", PtrVCB->VCBResource.ActiveCount, ++ PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); ++ ++ if( !ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) ++ { ++ // post the request to be processed in the context of a worker thread ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Write]", 0); ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ try_return(RC = STATUS_PENDING); ++ } ++ ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired [Write]", 0); ++ PtrResourceAcquired = &(PtrVCB->VCBResource); ++ } ++ ++ // Validate the caller supplied offset here ++ if( !PagingIo ) ++ { ++ if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart ) ++ { ++ // Write extending beyond the end of volume. ++ // Deny access... ++ // ++ RC = STATUS_END_OF_FILE; ++ NumberBytesWritten = 0; ++ try_return( RC ); ++ } ++ } ++ ++ // Lock the callers buffer ++ if (!NT_SUCCESS(RC = Ext2LockCallersBuffer(PtrIrp, TRUE, WriteLength))) ++ { ++ try_return(RC); ++ } ++ ++ // Forward the request to the lower level driver ++ if( PagingIo || NonBufferedIo ) ++ { ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "[Volume Write] PagingIo or NonBufferedIo ", 0); ++ CompleteIrp = FALSE; ++ ++ // ++ // Do the write operation... ++ // Send down the IRP to the lower level driver... ++ // ++ // Returned Informations and Status will be set by the lower level driver... ++ // The IRP will also be completed by the lower level driver... ++ ++ RC = Ext2PassDownSingleReadWriteIRP ( ++ PtrIrpContext, PtrIrp, PtrVCB, ++ ByteOffset, WriteLength, SynchronousIo ); ++ ++ try_return(RC); ++ } ++ else ++ { ++ PBCB PtrBCB = NULL; ++ PVOID PtrBuffer = NULL; ++ ++ DebugTrace(DEBUG_TRACE_READ_DETAILS, "[Volume Write] BufferedIo ", 0); ++ // ++ // Let the cache manager worry about this write... ++ // Pinned access should have been initiated. ++ // But checking anyway... ++ // ++ ASSERT( PtrVCB->PtrStreamFileObject ); ++ ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap ); ++ ++ CcPreparePinWrite( ++ PtrVCB->PtrStreamFileObject, ++ &ByteOffset, ++ WriteLength, ++ FALSE, // Don't Zero... ++ TRUE, // Can Wait... ++ &PtrBCB, ++ &PtrBuffer); ++ ++ // Do the write now... ++ // Write to the Pinned buffer... ++ // Cache Manager will do the disk write... ++ RtlCopyBytes( PtrBuffer, PtrSystemBuffer, WriteLength ); ++ // CcSetDirtyPinnedData( PtrBCB, NULL ); ++ CcUnpinData( PtrBCB ); ++ PtrBuffer = NULL; ++ PtrBCB = NULL; ++ ++ NumberBytesWritten = WriteLength; ++ ++ // Go ahead and complete the IRP... ++ } ++ try_return(RC); ++ } ++ ++ ++ IsThisADeferredWrite = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_DEFERRED_WRITE) ? TRUE : FALSE); ++ ++ if (!NonBufferedIo) ++ { ++ /**************************************************************************** ++ if (!CcCanIWrite(PtrFileObject, WriteLength, CanWait, IsThisADeferredWrite)) ++ { ++ // Cache Manager and/or the VMM does not want us to perform ++ // the write at this time. Post the request. ++ Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_DEFERRED_WRITE); ++ CcDeferWrite( PtrFileObject, Ext2DeferredWriteCallBack, PtrIrpContext, PtrIrp, WriteLength, IsThisADeferredWrite); ++ CompleteIrp = FALSE; ++ try_return( RC = STATUS_PENDING ); ++ } ++ ****************************************************************************/ ++ } ++ ++ // If the write request is directed to a page file ++ // send the request directly to the disk ++ // driver. For requests directed to a page file, you have to trust ++ // that the offsets will be set correctly by the VMM. You should not ++ // attempt to acquire any FSD resources either. ++ if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE) ++ { ++ IoMarkIrpPending(PtrIrp); ++ ++ // You will need to set a completion routine before invoking a lower level driver. ++ // Forward request directly to disk driver. ++ // Ext2PageFileIo(PtrIrpContext, PtrIrp); ++ ++ CompleteIrp = FALSE; ++ ++ try_return(RC = STATUS_PENDING); ++ } ++ ++ // Check whether this write operation is targeted ++ // to a directory object... ++ ++ if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY) ++ { ++ // ++ // Is this a write a result of ++ // cached directory manipulation operatio ++ // by the FSD itself? ++ // ++ if( PagingIo ) ++ { ++ // Yep! Allow it to proceed... ++ } ++ else ++ { ++ // Nope... User initiated directory writes are not allowed! ++ // Fail this request... ++ RC = STATUS_INVALID_DEVICE_REQUEST; ++ try_return(RC); ++ } ++ } ++ ++ PtrReqdFCB = &(PtrFCB->NTRequiredFCB); ++ ++ // ++ // Synchronizing with other reads and writes... ++ // Acquire the appropriate FCB resource exclusively ++ // ++ if (PagingIo) ++ { ++ // Try to acquire the FCB PagingIoResource exclusively ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCBpaging Exclusively [Write]", 0); ++ ++ if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait)) ++ { ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCBpaging Acquisition FAILED [Write]", 0); ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ try_return(RC = STATUS_PENDING); ++ } ++ // Remember the resource that was acquired ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCBpaging Acquired [Write]", 0); ++ PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource); ++ } ++ else ++ { ++ // Try to acquire the FCB MainResource exclusively ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Write]", 0); ++ if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait)) ++ { ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Write]", 0); ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ try_return(RC = STATUS_PENDING); ++ } ++ // Remember the resource that was acquired ++ DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquired [Write]", 0); ++ PtrResourceAcquired = &(PtrReqdFCB->MainResource); ++ } ++ ++ // Validate start offset and length supplied. ++ // Here is a special check that determines whether the caller wishes to ++ // begin the write at current end-of-file (whatever the value of that ++ // offset might be) ++ if ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == 0xFFFFFFFF)) ++ { ++ WritingAtEndOfFile = TRUE; ++ ByteOffset.QuadPart = PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart; ++ } ++ ++ // ++ // If this is a Non Cached io and if caching has been initiated, ++ // Flush and purge the cache ++ // ++ if (NonBufferedIo && !PagingIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL)) ++ { ++ // Flush and then attempt to purge the cache ++ CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, WriteLength, &(PtrIrp->IoStatus)); ++ // If the flush failed, return error to the caller ++ if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status)) ++ { ++ try_return(RC); ++ } ++ ++ // Attempt the purge and ignore the return code ++ CcPurgeCacheSection( &(PtrReqdFCB->SectionObject), (WritingAtEndOfFile ? &(PtrReqdFCB->CommonFCBHeader.FileSize) : &(ByteOffset)), ++ WriteLength, FALSE); ++ // We are finished with our flushing and purging ++ } ++ ++ if (!PagingIo) ++ { ++ // Insert code to perform the check here ... ++ // ++ // if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp, ++ // PtrCurrentIoStackLocation)) ++ // { ++ // try_return(RC = STATUS_FILE_LOCK_CONFLICT); ++ // } ++ } ++ ++ // Read in the File inode... ++ Ext2InitializeFCBInodeInfo( PtrFCB ); ++ ++ if (!PagingIo) ++ { ++ LARGE_INTEGER CurrentTime; ++ KeQuerySystemTime( &CurrentTime ); ++ PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart; ++ PtrFCB->LastWriteTime.QuadPart = CurrentTime.QuadPart; ++ } ++ ++ { ++ // ++ // Validate start offset and length supplied. ++ // ++ ULONG LogicalBlockSize = 0; ++ LONGLONG NoOfNewBlocksRequired = 0; ++ LONGLONG NoOfBytesRequired = 0; ++ LONGLONG i; ++ BOOLEAN ZeroOut = FALSE; ++ LARGE_INTEGER StartOffsetForZeroing; ++ LARGE_INTEGER EndOffsetForZeroing; ++ ++ ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ ++ if ( ByteOffset.QuadPart + WriteLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart ) ++ { ++ if( PagingIo ) ++ { ++ // ++ // A paging request never modifies the file size... ++ // ++ if( ByteOffset.QuadPart ++ >= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) ++ { ++ // Page request for writing outside the file... ++ // No op this IRP by completing it... ++ // ++ try_return(RC); ++ } ++ if( ByteOffset.QuadPart + WriteLength ++ > PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) ++ { ++ // Page request for writing outside the file alocation size... ++ // Truncate the write size so that it is within the allocation limit... ++ // ++ WriteLength = (ULONG) (PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart - ByteOffset.QuadPart); ++ } ++ } ++ else ++ { ++ ++ // Starting offset is > file size ++ // Allocate new blocks? ++ NoOfBytesRequired = ByteOffset.QuadPart + WriteLength ++ - PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart; ++ ++ if( NoOfBytesRequired ) ++ { ++ NoOfNewBlocksRequired = Ext2Align64( NoOfBytesRequired, LogicalBlockSize ) ++ / LogicalBlockSize; ++ for( i = 0; i < NoOfNewBlocksRequired ; i++ ) ++ { ++ Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE ); ++ } ++ ++ ZeroOut = TRUE; ++ ++ if( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart < ByteOffset.QuadPart ) ++ { ++ // Curr EOF --> | | <--New EOF ++ // ----------------------------------------------- ++ // | | |///////////| | ++ // | File Contents | Free |// Write //| Free | <- End of Allocation ++ // | | |///////////| | ++ // ----------------------------------------------- ++ // | | ++ ++ // Write is beyond the current end of file... ++ // This will create a hole... ++ // Will have to zero this out... ++ ++ // Start offset is the Current File size ++ StartOffsetForZeroing = PtrReqdFCB->CommonFCBHeader.FileSize; ++ // End offset is the point at which this write is going to start ++ EndOffsetForZeroing = ByteOffset; ++ } ++ else ++ { ++ // Curr EOF --> | | <--New EOF ++ // ------------------------------------------ ++ // | |///////////////| | ++ // | File Contents |//// Write ////| Free | <- End of Allocation ++ // | |///////////////| | ++ // ------------------------------------------ ++ // | | ++ ++ // Just zero out the end of the file ++ // not covered by the file size ++ ++ // Start offset is the New File size ++ StartOffsetForZeroing.QuadPart = ++ ByteOffset.QuadPart + WriteLength; ++ // End offset is the New Allocation size ++ EndOffsetForZeroing.QuadPart = PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart; ++ } ++ } ++ ++ PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart = ++ ByteOffset.QuadPart + WriteLength; ++ ++ ASSERT( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart <= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ); ++ ++ Ext2UpdateFileSize( PtrIrpContext, PtrFileObject, PtrFCB ); ++ ++ try ++ { ++ // ++ // Zero the blocks out... ++ // This routine can be used even if caching has not been initiated... ++ // ++ if( ZeroOut == TRUE && StartOffsetForZeroing.QuadPart != EndOffsetForZeroing.QuadPart ) ++ { ++ CcZeroData( PtrFileObject, ++ &StartOffsetForZeroing, ++ &EndOffsetForZeroing, ++ FALSE ); ++ ++ if( EndOffsetForZeroing.QuadPart != PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart ) ++ { ++ // Also zero out the file tip... ++ CcZeroData( PtrFileObject, ++ &PtrReqdFCB->CommonFCBHeader.FileSize, ++ &PtrReqdFCB->CommonFCBHeader.AllocationSize, ++ FALSE ); ++ } ++ } ++ } ++ finally ++ { ++ // Swallow an exceptions that are raised... ++ } ++ } ++ } ++ } ++ ++ // ++ // Branch here for cached vs non-cached I/O ++ // ++ if (!NonBufferedIo) ++ { ++ ++ // The caller wishes to perform cached I/O. ++ // Initiate caching if it hasn't been done already... ++ if (PtrFileObject->PrivateCacheMap == NULL) ++ { ++ CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), ++ FALSE, // We will not utilize pin access for this file ++ &(Ext2GlobalData.CacheMgrCallBacks), // callbacks ++ PtrCCB); // The context used in callbacks ++ } ++ ++ // Check and see if this request requires a MDL returned to the caller ++ if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL) ++ { ++ // Caller does want a MDL returned. Note that this mode ++ // implies that the caller is prepared to block ++ CcPrepareMdlWrite(PtrFileObject, &ByteOffset, WriteLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus)); ++ NumberBytesWritten = PtrIrp->IoStatus.Information; ++ RC = PtrIrp->IoStatus.Status; ++ ++ try_return(RC); ++ } ++ ++ // This is a regular run-of-the-mill cached I/O request. Let the ++ // Cache Manager worry about it! ++ ++ // First though, we need a buffer pointer (address) that is valid ++ PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp); ++ ASSERT(PtrSystemBuffer); ++ if ( !CcCopyWrite(PtrFileObject, &(ByteOffset), WriteLength, CanWait, PtrSystemBuffer)) ++ { ++ // The caller was not prepared to block and data is not immediately ++ // available in the system cache ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ // Mark Irp Pending ... ++ try_return(RC = STATUS_PENDING); ++ } ++ else ++ { ++ // We have the data ++ PtrIrp->IoStatus.Status = RC; ++ PtrIrp->IoStatus.Information = NumberBytesWritten = WriteLength; ++ } ++ } ++ else // NonBuffered or Paged IO ++ { ++ ++ ULONG Start = 0; ++ ULONG End = 0; ++ ULONG LogicalBlockIndex = 0; ++ ULONG BytesRemaining = 0; ++ ULONG BytesWrittenSoFar = 0; ++ ULONG LeftOver = 0; ++ ULONG LogicalBlockSize = 0; ++ ULONG PhysicalBlockSize = 0; ++ ULONG Index = 0; ++ ++ LONGLONG SingleIndirectBlockSize = 0; ++ LONGLONG DoubleIndirectBlockSize = 0; ++ LONGLONG TripleIndirectBlockSize = 0; ++ LONGLONG DirectBlockSize = 0; ++ ++ LONGLONG NoOfDirectBlocks ; ++ LONGLONG NoOfSingleIndirectBlocks ; ++ LONGLONG NoOfDoubleIndirectBlocks ; ++ LONGLONG NoOfTripleIndirectBlocks ; ++ ++ ULONG * PtrPinnedSIndirectBlock = NULL; ++ ULONG * PtrPinnedDIndirectBlock = NULL; ++ ULONG * PtrPinnedTIndirectBlock = NULL; ++ ++ // Used when reading a Triple Indirect Block... ++ LONGLONG FirstCachedDIBlockOffset = 0; ++ ++ // Used when reading a Double Indirect Block... ++ LONGLONG FirstCachedSIBlockOffset = 0; ++ ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "[File Write] Paging IO or NonBufferedIo ", 0); ++ ++ // Calculating where the write should start from... ++ LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; ++ PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize; ++ ++ NoOfDirectBlocks = EXT2_NDIR_BLOCKS ; ++ NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG ); ++ NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); ++ NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG ); ++ ++ DirectBlockSize = LogicalBlockSize * NoOfDirectBlocks; ++ SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks; ++ DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ; ++ TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks; ++ ++ LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize); ++ ++ if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) ++ { ++ // ++ // Handle Triple indirect blocks? ++ // A Pop up will do for now... ++ // ++ UNICODE_STRING ErrorMessage; ++ Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" ); ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "@@@@@@@@ Triple indirect blocks need to be written to! \n@@@@@@@@ This is not supported as yet!", 0); ++ /* REACTOS FIXME */ ++ IoRaiseInformationalHardError( ++ /* IO_ERR_DRIVER_ERROR */(NTSTATUS)0xC0040004L, ++ &ErrorMessage, ++ KeGetCurrentThread( ) ); ++ ++ Ext2DeallocateUnicodeString( &ErrorMessage ); ++ RC = STATUS_INSUFFICIENT_RESOURCES; ++ try_return ( RC ); ++ } ++ ++ if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize && ++ ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) ) ++ { ++ LARGE_INTEGER VolumeByteOffset; ++ ++ // ++ // Indirect Blocks required... ++ // Read in the single indirect blocks... ++ // ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "Reading in some Indirect Blocks", 0); ++ ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_NDIR_BLOCKS ] * LogicalBlockSize; ++ ++ // ++ // Asking the cache manager to oblige by pinning the single indirect block... ++ // ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ CanWait, ++ &PtrPinnedSIndirectBCB, ++ (PVOID*)&PtrPinnedSIndirectBlock )) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ ++ // Mark Irp Pending ... ++ IoMarkIrpPending( PtrIrp ); ++ RC = STATUS_PENDING; ++ try_return(RC); ++ DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data", 0); ++ } ++ } ++ if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize && ++ ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) ++ { ++ // ++ // Double Indirect Blocks required... ++ // Read in the double indirect blocks... ++ // ++ ++ LONGLONG StartIndirectBlock; ++ LONGLONG EndIndirectBlock; ++ ++ ++ ++ LARGE_INTEGER VolumeByteOffset; ++ ++ DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0); ++ ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; ++ ++ // ++ // Asking the cache manager to oblige by pinning the double indirect block... ++ // ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ CanWait, ++ &PtrPinnedDIndirectBCB, ++ (PVOID*)&PtrPinnedDIndirectBlock )) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ ++ // Mark Irp Pending ... ++ IoMarkIrpPending( PtrIrp ); ++ RC = STATUS_PENDING; ++ try_return(RC); ++ DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); ++ } ++ ++ // So far so good... ++ // Now determine the single indirect blocks that will have to be read in... ++ if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize ) ++ { ++ // Request doesnot require any single indirect or direct blocks ++ StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize); ++ StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; ++ StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; ++ } ++ else ++ { ++ StartIndirectBlock = 0; ++ } ++ ++ FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks; ++ ++ if( ByteOffset.QuadPart + WriteLength >= ++ DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize) ++ { ++ EndIndirectBlock = DoubleIndirectBlockSize; ++ } ++ else ++ { ++ EndIndirectBlock = ByteOffset.QuadPart + WriteLength - ++ (DirectBlockSize + SingleIndirectBlockSize); ++ } ++ EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; ++ EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; ++ ++ DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock); ++ ++ PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); ++ { ++ ULONG i; ++ ++ for( i = 0; i < DIArrayCount; i++ ) ++ { ++ VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ CanWait, ++ &PtrDIArray[i].PtrBCB, ++ (PVOID*)&PtrDIArray[i].PtrSIBlocks)) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ IoMarkIrpPending( PtrIrp ); ++ DIArrayCount = i; ++ try_return(RC = STATUS_PENDING); ++ ++ DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); ++ } ++ } ++ } ++ } ++ ++/* { ++ // ++ // Double Indirect Blocks required... ++ // Read in the double indirect blocks... ++ // ++ ++ LONGLONG StartIndirectBlock; ++ LONGLONG EndIndirectBlock; ++ ++ LARGE_INTEGER VolumeByteOffset; ++ ++ DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0); ++ ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize; ++ ++ // ++ // Asking the cache manager to oblige by pinning the double indirect block... ++ // ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ CanWait, ++ &PtrPinnedDIndirectBCB, ++ (PVOID*)&PtrPinnedDIndirectBlock )) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ ++ // Mark Irp Pending ... ++ IoMarkIrpPending( PtrIrp ); ++ RC = STATUS_PENDING; ++ try_return(RC); ++ DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); ++ } ++ ++ // So far so good... ++ // Now determine the single indirect blocks that will have to be read in... ++ if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize ) ++ { ++ // Request doesnot require any single indirect or direct blocks ++ StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize); ++ StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; ++ StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; ++ } ++ else ++ { ++ StartIndirectBlock = 0; ++ } ++ ++ if( ByteOffset.QuadPart + WriteLength >= ++ DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize) ++ { ++ EndIndirectBlock = DoubleIndirectBlockSize; ++ } ++ else ++ { ++ EndIndirectBlock = ByteOffset.QuadPart + WriteLength - ++ (DirectBlockSize + SingleIndirectBlockSize); ++ if( EndIndirectBlock % LogicalBlockSize ) ++ { ++ EndIndirectBlock += LogicalBlockSize; ++ } ++ EndIndirectBlock = EndIndirectBlock / LogicalBlockSize; ++ if( EndIndirectBlock % NoOfSingleIndirectBlocks) ++ { ++ EndIndirectBlock += NoOfSingleIndirectBlocks; ++ } ++ EndIndirectBlock = EndIndirectBlock / NoOfSingleIndirectBlocks; ++ } ++ DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock); ++ PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); ++ { ++ ULONG i; ++ ++ for( i = 0; i < DIArrayCount; i++ ) ++ { ++ VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize; ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ CanWait, ++ &PtrDIArray[i].PtrBCB, ++ (PVOID*)&PtrDIArray[i].PtrSIBlocks)) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ IoMarkIrpPending( PtrIrp ); ++ DIArrayCount = i; ++ try_return(RC = STATUS_PENDING); ++ ++ DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); ++ } ++ } ++ } ++ } ++*/ ++ if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) ++ { ++ // ++ // Triple Indirect Blocks required... ++ // Read in the triple indirect blocks... ++ // ++ LONGLONG StartTIndirectBlock; ++ LONGLONG EndTIndirectBlock; ++ ++ LONGLONG StartDIndirectBlock; ++ LONGLONG EndDIndirectBlock; ++ LONGLONG StartIndirectBlock; ++ LONGLONG EndIndirectBlock; ++ ++ LONGLONG ByteOffsetTillHere = 0; ++ ++ PBCB TempDIBCB; ++ LONG* TempDIBuffer; ++ ++ ULONG TIArrayIndex = 0; ++ ++ LARGE_INTEGER VolumeByteOffset; ++ ++ DebugTrace(DEBUG_TRACE_MISC, "Reading in some Triple Indirect Blocks", 0); ++ ++ VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize; ++ ++ DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffset = 0x%I64X", ByteOffset ); ++ DebugTrace(DEBUG_TRACE_TRIPLE, "WriteLength = 0x%lX", WriteLength ); ++ DebugTrace(DEBUG_TRACE_TRIPLE, "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] ); ++ // ++ // Asking the cache manager to oblige by pinning the triple indirect block... ++ // ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ CanWait, ++ &PtrPinnedTIndirectBCB, ++ (PVOID*)&PtrPinnedTIndirectBlock )) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ ++ // Mark Irp Pending ... ++ IoMarkIrpPending( PtrIrp ); ++ RC = STATUS_PENDING; ++ try_return(RC); ++ DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); ++ } ++ ++ // Determine the no of BCBs that need to be saved... ++ if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) ++ { ++ StartTIndirectBlock = ByteOffset.QuadPart; ++ } ++ else ++ { ++ StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; ++ } ++ EndTIndirectBlock = ByteOffset.QuadPart + WriteLength; ++ TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2; ++ ++ ++ PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) ); ++ ++ // Now determine the double indirect blocks that will have to be read in... ++ if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize ) ++ { ++ // Request doesnot require any single indirect or direct blocks ++ StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); ++ StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize; ++ StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks; ++ ++ ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ; ++ //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize; ++ FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; ++ } ++ else ++ { ++ ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize; ++ FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize; ++ StartDIndirectBlock = 0; ++ } ++ ++ DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere ); ++ ++ EndDIndirectBlock = ByteOffset.QuadPart + WriteLength - ++ (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize); ++ EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ; ++ EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks; ++ ++ { ++ // Reading in the necessary double indirect bocks... ++ ULONG i; ++ LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock; ++ ++ for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize) ++ { ++ VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize; ++ ++ DebugTrace(DEBUG_TRACE_TRIPLE, "Double VolOffset = 0x%I64X", VolumeByteOffset ); ++ ++ if( !CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ CanWait, ++ &TempDIBCB, ++ (PVOID*)&TempDIBuffer) ) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ IoMarkIrpPending( PtrIrp ); ++ try_return(RC = STATUS_PENDING); ++ DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); ++ } ++ ++ if( ByteOffset.QuadPart > ByteOffsetTillHere) ++ { ++ StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere); ++ StartIndirectBlock = StartIndirectBlock / LogicalBlockSize; ++ StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks; ++ ++ if( TIArrayIndex == 0 ) ++ { ++ FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks; ++ } ++ } ++ else ++ { ++ StartIndirectBlock = 0; ++ } ++ ++ if( ByteOffset.QuadPart + WriteLength >= ByteOffsetTillHere + DoubleIndirectBlockSize) ++ { ++ EndIndirectBlock = DoubleIndirectBlockSize; ++ } ++ else ++ { ++ EndIndirectBlock = ByteOffset.QuadPart + WriteLength - ByteOffsetTillHere; ++ } ++ EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ; ++ EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks; ++ ++ { ++ ULONG i; ++ ++ for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ ) ++ { ++ VolumeByteOffset.QuadPart = TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize; ++ DebugTrace(DEBUG_TRACE_TRIPLE, "Single VolOffset = 0x%I64X", VolumeByteOffset ); ++ ++ if (!CcMapData( PtrVCB->PtrStreamFileObject, ++ &VolumeByteOffset, ++ LogicalBlockSize, ++ CanWait, ++ &PtrTIArray[ TIArrayIndex ].PtrBCB, ++ (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks)) ++ { ++ CompleteIrp = FALSE; ++ PostRequest = TRUE; ++ IoMarkIrpPending( PtrIrp ); ++ DIArrayCount = i; ++ try_return(RC = STATUS_PENDING); ++ ++ DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0); ++ } ++ TIArrayIndex++; ++ } ++ } ++ CcUnpinData( TempDIBCB ); ++ TempDIBCB = NULL; ++ TempDIBuffer = NULL; ++ } ++ } ++ TIArrayCount = TIArrayIndex; ++ ++ DebugTrace(DEBUG_TRACE_TRIPLE, "TIArrayCount = %ld", TIArrayCount ); ++ DebugTrace(DEBUG_TRACE_TRIPLE, "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset ); ++ } ++ ++ // ++ // Allocating memory for IO Runs ++ // ++ Index = ( (WriteLength - 2) / LogicalBlockSize + 2 ); ++ PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) ) ); ++ ++ ++ Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) ); ++ BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart ); ++ ++ if( WriteLength > BytesRemaining ) ++ End = Start + BytesRemaining; ++ else ++ End = Start + WriteLength; ++ BytesWrittenSoFar = 0; ++ ++ Index = 0; ++ DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "\nDetermining the write IRPs that have to be passed down...", 0); ++ ++ while( 1 ) ++ { ++ BytesWrittenSoFar += (End-Start); ++ if( LogicalBlockIndex < EXT2_NDIR_BLOCKS ) ++ { ++ // Direct Block ++ PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ]; ++ } ++ else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) ++ { ++ // Single Indirect Block ++ PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - EXT2_NDIR_BLOCKS ]; ++ } ++ else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks) ) ++ { ++ LONGLONG BlockNo; ++ LONGLONG IBlockIndex; ++ LONGLONG BlockIndex; ++ ++ BlockNo = LogicalBlockIndex - FirstCachedSIBlockOffset; ++ IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; ++ BlockIndex = BlockNo % NoOfSingleIndirectBlocks; ++ ++ // Double Indirect Block ++ PtrIoRuns[ Index ].LogicalBlock = ++ PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ]; ++ } ++ else ++ { ++ // Triple Indirect Block ++ LONGLONG BlockNo; ++ LONGLONG IBlockIndex; ++ LONGLONG BlockIndex; ++ BlockNo = LogicalBlockIndex - FirstCachedDIBlockOffset; ++ IBlockIndex = BlockNo / NoOfSingleIndirectBlocks; ++ BlockIndex = BlockNo % NoOfSingleIndirectBlocks; ++ ++ DbgPrint( "\nBlock No : 0x%I64X IBlockIndex = 0x%I64X BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex); ++ ++ if( IBlockIndex >= TIArrayCount ) ++ { ++ Ext2BreakPoint(); ++ } ++ if( BlockIndex >= LogicalBlockSize ) ++ { ++ Ext2BreakPoint(); ++ } ++ ++ PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];; ++ DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock ); ++ } ++ ++ if( PtrIoRuns[ Index ].LogicalBlock == 0 ) ++ { ++ // ++ // Something is wrong... ++ // ++ Ext2BreakPoint(); ++ break; ++ ++ } ++ PtrIoRuns[ Index ].StartOffset = Start; ++ PtrIoRuns[ Index ].EndOffset = End; ++ PtrIoRuns[ Index ].PtrAssociatedIrp = NULL; ++ ++ DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Index = (%ld)", LogicalBlockIndex ); ++ DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Logical Block = (0x%lX)", PtrFCB->IBlock[ LogicalBlockIndex ] ); ++ DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Start = (0x%lX)", Start ); ++ DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " End = (0x%lX) ", End ); ++ DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Bytes written (0x%lX)", BytesWrittenSoFar ); ++ ++ ++ ++ if( BytesWrittenSoFar >= WriteLength ) ++ break; ++ LogicalBlockIndex++; ++ Start = 0; ++ LeftOver = WriteLength - BytesWrittenSoFar; ++ if( LeftOver > LogicalBlockSize ) ++ End = LogicalBlockSize; ++ else ++ End = LeftOver; ++ // Loop over to make the write request... ++ Index++; ++ } ++ ++ // ++ // Unpin the Indirect Blocks ++ // ++ if( PtrPinnedSIndirectBCB ) ++ { ++ CcUnpinData( PtrPinnedSIndirectBCB ); ++ PtrPinnedSIndirectBCB = NULL; ++ PtrPinnedSIndirectBlock = NULL; ++ } ++ if( PtrPinnedDIndirectBCB ) ++ { ++ CcUnpinData( PtrPinnedDIndirectBCB ); ++ PtrPinnedDIndirectBCB = NULL; ++ PtrPinnedDIndirectBlock = NULL; ++ } ++ // ++ // Pass down Associated IRPs to the Target Device Driver... ++ // ++ DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "Passing down the Write IRPs to the disk driver...", 0 ); ++ ++ RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, WriteLength, PtrIrpContext, PtrFCB, SynchronousIo ); ++ ++ // ++ // Irp will be completed automatically ++ // when all the Associated IRPs are completed ++ // ++ if( RC == STATUS_SUCCESS || RC == STATUS_PENDING ) ++ { ++ CompleteIrp = FALSE; ++ } ++ try_return( RC ); ++ } ++ ++ try_exit: NOTHING; ++ ++ } ++ finally ++ { ++ if ( PtrIoRuns ) ++ { ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Write]", PtrIoRuns ); ++ ExFreePool( PtrIoRuns ); ++ } ++ if( PtrPinnedSIndirectBCB ) ++ { ++ CcUnpinData( PtrPinnedSIndirectBCB ); ++ PtrPinnedSIndirectBCB = NULL; ++ } ++ if( PtrPinnedDIndirectBCB ) ++ { ++ CcUnpinData( PtrPinnedDIndirectBCB ); ++ PtrPinnedDIndirectBCB = NULL; ++ } ++ if ( PtrDIArray ) ++ { ++ ULONG i; ++ for( i = 0; i < DIArrayCount; i++ ) ++ { ++ CcUnpinData( PtrDIArray->PtrBCB ); ++ } ++ DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrDIArray ); ++ ExFreePool( PtrDIArray ); ++ PtrDIArray = NULL; ++ } ++ // Release resources ... ++ // ++ if (PtrResourceAcquired) ++ { ++ Ext2ReleaseResource(PtrResourceAcquired); ++ ++ DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** Resource Released [Write]", 0); ++ DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Write]", ++ PtrResourceAcquired->ActiveCount, ++ PtrResourceAcquired->NumberOfExclusiveWaiters, ++ PtrResourceAcquired->NumberOfSharedWaiters ); ++ ++ if( PtrFileObject ) ++ { ++ DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Write]", PtrFileObject); ++ } ++ if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Write]", 0); ++ } ++ else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Released [Write]", 0); ++ } ++ else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB Paging Resource Released [Write]", 0); ++ } ++ else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) ) ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** FCB Resource Released [Write]", 0); ++ } ++ else ++ { ++ DebugTrace(DEBUG_TRACE_MISC, "*** Unknown Resource Released [Write]", 0); ++ } ++ ++ PtrResourceAcquired = NULL; ++ } ++ ++ if (PostRequest) ++ { ++ RC = Ext2PostRequest(PtrIrpContext, PtrIrp); ++ } ++ else if ( CompleteIrp && !(RC == STATUS_PENDING)) ++ { ++ // For synchronous I/O, the FSD must maintain the current byte offset ++ // Do not do this however, if I/O is marked as paging-io ++ if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) ++ { ++ PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset, ++ RtlConvertUlongToLargeInteger((unsigned long)NumberBytesWritten)); ++ } ++ ++ // If the write completed successfully and this was not a paging-io ++ // operation, set a flag in the CCB that indicates that a write was ++ // performed and that the file time should be updated at cleanup ++ if (NT_SUCCESS(RC) && !PagingIo) ++ { ++ Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_MODIFIED); ++ } ++ ++ // If the file size was changed, set a flag in the FCB indicating that ++ // this occurred. ++ ++ // If the request failed, and we had done some nasty stuff like ++ // extending the file size (including informing the Cache Manager ++ // about the new file size), and allocating on-disk space etc., undo ++ // it at this time. ++ ++ // Can complete the IRP here if no exception was encountered ++ if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) ++ { ++ PtrIrp->IoStatus.Status = RC; ++ PtrIrp->IoStatus.Information = NumberBytesWritten; ++ ++ // complete the IRP ++ IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); ++ } ++ ++ // Free up the Irp Context ++ Ext2ReleaseIrpContext(PtrIrpContext); ++ ++ } // can we complete the IRP ? ++ else ++ { ++ // Free up the Irp Context ++ Ext2ReleaseIrpContext(PtrIrpContext); ++ } ++ } // end of "finally" processing ++ return(RC); ++} ++ ++ ++/************************************************************************* ++* ++* Function: Ext2DeferredWriteCallBack() ++* ++* Description: ++* Invoked by the cache manager in the context of a worker thread. ++* Typically, you can simply post the request at this point (just ++* as you would have if the original request could not block) to ++* perform the write in the context of a system worker thread. ++* ++* Expected Interrupt Level (for execution) : ++* ++* IRQL_PASSIVE_LEVEL ++* ++* Return Value: None ++* ++*************************************************************************/ ++void Ext2DeferredWriteCallBack ( ++void *Context1, // Should be PtrIrpContext ++void *Context2 ) // Should be PtrIrp ++{ ++ // You should typically simply post the request to your internal ++ // queue of posted requests (just as you would if the original write ++ // could not be completed because the caller could not block). ++ // Once you post the request, return from this routine. The write ++ // will then be retried in the context of a system worker thread ++} diff --cc reactos/drivers/filesystems/fs_rec/ext2.c index 00000000000,2fa7339cadb..2fa7339cadb mode 000000,100644..100644 --- a/reactos/drivers/filesystems/fs_rec/ext2.c +++ b/reactos/drivers/filesystems/fs_rec/ext2.c diff --cc reactos/include/reactos/libs/fslib/ext2lib.h index 00000000000,58390b0310a..58390b0310a mode 000000,100644..100644 --- a/reactos/include/reactos/libs/fslib/ext2lib.h +++ b/reactos/include/reactos/libs/fslib/ext2lib.h diff --cc reactos/lib/fslib/ext2lib/Badblock.c index 00000000000,642c1bd8fd7..28567b24cd1 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Badblock.c +++ b/reactos/lib/fslib/ext2lib/Badblock.c @@@ -1,0 -1,43 +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; -} ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Bitmap.c index 00000000000,bc2746ad533..cf5a15713c8 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Bitmap.c +++ b/reactos/lib/fslib/ext2lib/Bitmap.c @@@ -1,0 -1,499 +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); -} - ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Bitmap.h index 00000000000,d6569d09ca9..cbac01c8ddd mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Bitmap.h +++ b/reactos/lib/fslib/ext2lib/Bitmap.h @@@ -1,0 -1,12 +1,12 @@@ -#ifndef _BITMAP_H - -#include "time.h" -#include "stdio.h" -#include "stdlib.h" -#include "string.h" -#include "windows.h" - - - - -#endif // _BITMAP_H ++#ifndef _BITMAP_H ++ ++#include "time.h" ++#include "stdio.h" ++#include "stdlib.h" ++#include "string.h" ++#include "windows.h" ++ ++ ++ ++ ++#endif // _BITMAP_H diff --cc reactos/lib/fslib/ext2lib/Disk.c index 00000000000,ee325035002..1930aad4952 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Disk.c +++ b/reactos/lib/fslib/ext2lib/Disk.c @@@ -1,0 -1,1352 +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; -} ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Disk.h index 00000000000,f824a034edf..d23a14a4b33 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Disk.h +++ b/reactos/lib/fslib/ext2lib/Disk.h @@@ -1,0 -1,19 +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_ */ ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Group.c index 00000000000,9f364b3f982..68ea9745651 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Group.c +++ b/reactos/lib/fslib/ext2lib/Group.c @@@ -1,0 -1,68 +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; - } -} ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Inode.c index 00000000000,64d95a9474e..9b235978c70 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Inode.c +++ b/reactos/lib/fslib/ext2lib/Inode.c @@@ -1,0 -1,697 +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; -} ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Memory.c index 00000000000,c5277db6219..08e59f79b98 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Memory.c +++ b/reactos/lib/fslib/ext2lib/Memory.c @@@ -1,0 -1,416 +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; -} ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Mke2fs.c index 00000000000,8608d275c20..9434371b875 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Mke2fs.c +++ b/reactos/lib/fslib/ext2lib/Mke2fs.c @@@ -1,0 -1,1010 +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; -} ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Mke2fs.h index 00000000000,a0353bd576c..ea05d529c01 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Mke2fs.h +++ b/reactos/lib/fslib/ext2lib/Mke2fs.h @@@ -1,0 -1,876 +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__ ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Super.c index 00000000000,8d0b36e69de..0b09490efda mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Super.c +++ b/reactos/lib/fslib/ext2lib/Super.c @@@ -1,0 -1,302 +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; -} ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/Uuid.c index 00000000000,1e029da18db..5284cd94b1b mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/Uuid.c +++ b/reactos/lib/fslib/ext2lib/Uuid.c @@@ -1,0 -1,25 +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 -} ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/ext2_fs.h index 00000000000,05ab2d84420..be4cafa5ae7 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/ext2_fs.h +++ b/reactos/lib/fslib/ext2lib/ext2_fs.h @@@ -1,0 -1,657 +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 */ ++/* ++ * 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 --cc reactos/lib/fslib/ext2lib/types.h index 00000000000,dbc445484ec..a874df5b564 mode 000000,100644..100644 --- a/reactos/lib/fslib/ext2lib/types.h +++ b/reactos/lib/fslib/ext2lib/types.h @@@ -1,0 -1,10 +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 */ ++#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 */