[EXT2]
authorPierre Schweitzer <pierre@reactos.org>
Sun, 20 Mar 2016 18:36:38 +0000 (18:36 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Sun, 20 Mar 2016 18:36:38 +0000 (18:36 +0000)
Update the driver to release 0.63.

One notable change is support for ExtX links (hard/sym). They work out of the box due to all the previous work that was done for supporting reparse points on NTFS.

Full changelog available at: http://www.ext2fsd.com/?p=195

CORE-10996 #resolve #comment Commited in r71031

svn path=/trunk/; revision=71031

35 files changed:
reactos/drivers/filesystems/ext2/CMakeLists.txt
reactos/drivers/filesystems/ext2/inc/ext2fs.h
reactos/drivers/filesystems/ext2/inc/linux/ext3_fs_sb.h
reactos/drivers/filesystems/ext2/inc/linux/ext4_ext.h
reactos/drivers/filesystems/ext2/inc/linux/fs.h
reactos/drivers/filesystems/ext2/inc/linux/jbd.h
reactos/drivers/filesystems/ext2/inc/linux/module.h
reactos/drivers/filesystems/ext2/inc/linux/rbtree.h
reactos/drivers/filesystems/ext2/src/access.c [new file with mode: 0644]
reactos/drivers/filesystems/ext2/src/cleanup.c
reactos/drivers/filesystems/ext2/src/close.c
reactos/drivers/filesystems/ext2/src/create.c
reactos/drivers/filesystems/ext2/src/debug.c
reactos/drivers/filesystems/ext2/src/dirctl.c
reactos/drivers/filesystems/ext2/src/ext3/generic.c
reactos/drivers/filesystems/ext2/src/ext3/htree.c
reactos/drivers/filesystems/ext2/src/ext3/recover.c
reactos/drivers/filesystems/ext2/src/ext4/ext4_bh.c
reactos/drivers/filesystems/ext2/src/ext4/ext4_extents.c
reactos/drivers/filesystems/ext2/src/ext4/extents.c
reactos/drivers/filesystems/ext2/src/fastio.c
reactos/drivers/filesystems/ext2/src/fileinfo.c
reactos/drivers/filesystems/ext2/src/flush.c
reactos/drivers/filesystems/ext2/src/fsctl.c
reactos/drivers/filesystems/ext2/src/init.c
reactos/drivers/filesystems/ext2/src/jbd/replay.c
reactos/drivers/filesystems/ext2/src/jbd/revoke.c
reactos/drivers/filesystems/ext2/src/linux.c
reactos/drivers/filesystems/ext2/src/lock.c
reactos/drivers/filesystems/ext2/src/memory.c
reactos/drivers/filesystems/ext2/src/misc.c
reactos/drivers/filesystems/ext2/src/pnp.c
reactos/drivers/filesystems/ext2/src/read.c
reactos/drivers/filesystems/ext2/src/volinfo.c
reactos/drivers/filesystems/ext2/src/write.c

index ec64b1a..63bf2de 100644 (file)
@@ -56,6 +56,7 @@ list(APPEND SOURCE
     src/nls/nls_koi8-ru.c
     src/nls/nls_koi8-u.c
     src/nls/nls_utf8.c
+    src/access.c
     src/block.c
     src/cleanup.c
     src/close.c
index c695df2..eb806f3 100644 (file)
@@ -4,7 +4,7 @@
  * FILE:             Ext2fs.h
  * PURPOSE:          Header file: ext2 structures
  * PROGRAMMER:       Matt Wu <mattwu@163.com>
- * HOMEPAGE:         http://ext2.yeah.net
+ * HOMEPAGE:         http://www.ext2fsd.com
  * UPDATE HISTORY:
  */
 
@@ -18,7 +18,8 @@
 #include <ndk/rtlfuncs.h>
 #include <pseh/pseh2.h>
 #endif
-#include "stdio.h"
+#include <stdio.h>
+#include <time.h>
 #include <string.h>
 #include <linux/ext2_fs.h>
 #include <linux/ext3_fs.h>
 
 /* STRUCTS & CONSTS******************************************************/
 
-#define EXT2FSD_VERSION                 "0.62"
+#define EXT2FSD_VERSION                 "0.63"
 
 
+/* WDK DEFINITIONS ******************************************************/
+
+
+/* COMPILER SWITCH / OPTIONS ********************************************/
+
 //
 // Ext2Fsd build options
 //
@@ -378,10 +384,25 @@ Ext2ClearFlag(PULONG Flags, ULONG FlagBit)
 #define Ext2SetOwnerReadOnly(m) do {(m) &= ~S_IWUSR;} while(0)
 
 #define Ext2IsOwnerWritable(m)  (((m) & S_IWUSR) == S_IWUSR)
-#define Ext2IsOwnerReadOnly(m)  (!(Ext2IsOwnerWritable(m)))
+#define Ext2IsOwnerReadable(m)  (((m) & S_IRUSR) == S_IRUSR)
+#define Ext2IsOwnerReadOnly(m)  (!(Ext2IsOwnerWritable(m)) && Ext2IsOwnerReadable(m))
+
+#define Ext2IsGroupWritable(m)  (((m) & S_IWGRP) == S_IWGRP)
+#define Ext2IsGroupReadable(m)  (((m) & S_IRGRP) == S_IRGRP)
+#define Ext2IsGroupReadOnly(m)  (!(Ext2IsGroupWritable(m)) && Ext2IsGroupReadable(m))
+
+#define Ext2IsOtherWritable(m)  (((m) & S_IWOTH) == S_IWOTH)
+#define Ext2IsOtherReadable(m)  (((m) & S_IROTH) == S_IROTH)
+#define Ext2IsOtherReadOnly(m)  (!(Ext2IsOtherWritable(m)) && Ext2IsOtherReadable(m))
 
 #define Ext2SetReadOnly(m) do {(m) &= ~(S_IWUSR | S_IWGRP | S_IWOTH);} while(0)
 
+
+#define Ext2FileCanRead         (0x1)
+#define Ext2FileCanWrite        (0x2)
+#define Ext2FileCanExecute      (0x4)
+
+
 /*
  * We need 8-bytes aligned for all the sturctures
  * It's a must for all ERESOURCE allocations
@@ -690,6 +711,14 @@ typedef struct _EXT2_VCB {
     BOOLEAN                     bHidingSuffix;
     CHAR                        sHidingSuffix[HIDINGPAT_LEN];
 
+    /* User to impersanate */
+    uid_t                       uid;
+    gid_t                       gid;
+
+    /* User to act as */
+    uid_t                       euid;
+    gid_t                       egid;
+
     /* mountpoint: symlink to DesDevices */
     UCHAR                       DrvLetter;
 
@@ -713,6 +742,8 @@ typedef struct _EXT2_VCB {
 #define VCB_DISMOUNT_PENDING    0x00000008
 #define VCB_NEW_VPB             0x00000010
 #define VCB_BEING_CLOSED        0x00000020
+#define VCB_USER_IDS            0x00000040  /* uid/gid specified by user */
+#define VCB_USER_EIDS           0x00000080  /* euid/egid specified by user */
 
 #define VCB_FORCE_WRITING       0x00004000
 #define VCB_DEVICE_REMOVED      0x00008000
@@ -816,7 +847,7 @@ struct _EXT2_MCB {
 
     // Link List Info
     PEXT2_MCB                       Parent; // Parent
-    PEXT2_MCB                       Next;   // Brothers
+    PEXT2_MCB                       Next;   // Siblings
 
     union {
         PEXT2_MCB                   Child;  // Children Mcb nodes
@@ -943,7 +974,7 @@ typedef struct _EXT2_CCB {
 #define CCB_FROM_POOL               0x00000001
 #define CCB_VOLUME_DASD_PURGE       0x00000002
 #define CCB_LAST_WRITE_UPDATED      0x00000004
-
+#define CCB_OPEN_REPARSE_POINT      0x00000008
 #define CCB_DELETE_ON_CLOSE         0x00000010
 
 #define CCB_ALLOW_EXTENDED_DASD_IO  0x80000000
@@ -1102,6 +1133,14 @@ typedef struct _EXT2_FILLDIR_CONTEXT {
     BOOLEAN                 efc_single;
 } EXT2_FILLDIR_CONTEXT, *PEXT2_FILLDIR_CONTEXT;
 
+//
+// Access.c
+//
+
+
+int Ext2CheckInodeAccess(PEXT2_VCB Vcb, struct inode *in, int attempt);
+int Ext2CheckFileAccess (PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt);
+
 //
 // Block.c
 //
@@ -1268,7 +1307,7 @@ Ext2FollowLink (
     IN PEXT2_VCB            Vcb,
     IN PEXT2_MCB            Parent,
     IN PEXT2_MCB            Mcb,
-    IN USHORT               Linkdep
+    IN ULONG                Linkdep
 );
 
 NTSTATUS
@@ -1287,6 +1326,9 @@ Ext2IsSpecialSystemFile(
     IN BOOLEAN         bDirectory
 );
 
+#define EXT2_LOOKUP_FLAG_MASK   (0xFF00000)
+#define EXT2_LOOKUP_NOT_FOLLOW  (0x8000000)
+
 NTSTATUS
 Ext2LookupFile (
     IN PEXT2_IRP_CONTEXT    IrpContext,
@@ -1294,7 +1336,7 @@ Ext2LookupFile (
     IN PUNICODE_STRING      FullName,
     IN PEXT2_MCB            Parent,
     OUT PEXT2_MCB *         Ext2Mcb,
-    IN USHORT               Linkdep
+    IN ULONG                Linkdep
 );
 
 NTSTATUS
@@ -1733,6 +1775,9 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb);
 VOID
 Ext2PutGroup(IN PEXT2_VCB Vcb);
 
+VOID
+Ext2DropGroup(IN PEXT2_VCB Vcb);
+
 BOOLEAN
 Ext2SaveGroup(
     IN PEXT2_IRP_CONTEXT    IrpContext,
@@ -1884,6 +1929,14 @@ Ext2AddEntry (
     OUT struct dentry    **dentry
 );
 
+NTSTATUS
+Ext2SetFileType (
+    IN PEXT2_IRP_CONTEXT    IrpContext,
+    IN PEXT2_VCB            Vcb,
+    IN PEXT2_FCB            Dcb,
+    IN PEXT2_MCB            Mcb
+);
+
 NTSTATUS
 Ext2RemoveEntry (
     IN PEXT2_IRP_CONTEXT    IrpContext,
@@ -2116,6 +2169,14 @@ Ext2SetRenameInfo(
     PEXT2_CCB Ccb
 );
 
+NTSTATUS
+Ext2SetLinkInfo(
+    PEXT2_IRP_CONTEXT IrpContext,
+    PEXT2_VCB Vcb,
+    PEXT2_FCB Fcb,
+    PEXT2_CCB Ccb
+);
+
 ULONG
 Ext2InodeType(PEXT2_MCB Mcb);
 
@@ -2161,6 +2222,34 @@ Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext);
 // Fsctl.c
 //
 
+NTSTATUS
+Ext2ReadSymlink (
+    IN PEXT2_IRP_CONTEXT    IrpContext,
+    IN PEXT2_VCB            Vcb,
+    IN PEXT2_MCB            Mcb,
+    IN PVOID                Buffer,
+    IN ULONG                Size,
+    OUT PULONG              BytesRead
+    );
+
+NTSTATUS
+Ext2WriteSymlink (
+    IN PEXT2_IRP_CONTEXT    IrpContext,
+    IN PEXT2_VCB            Vcb,
+    IN PEXT2_MCB            Mcb,
+    IN PVOID                Buffer,
+    IN ULONG                Size,
+    OUT PULONG              BytesWritten
+);
+
+NTSTATUS
+Ext2TruncateSymlink(
+    PEXT2_IRP_CONTEXT IrpContext,
+    PEXT2_VCB         Vcb,
+    PEXT2_MCB         Mcb,
+    ULONG             Size
+);
+
 //
 // MountPoint process workitem
 //
@@ -2400,7 +2489,7 @@ VOID
 Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb);
 
 PEXT2_CCB
-Ext2AllocateCcb (PEXT2_MCB  SymLink);
+Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink);
 
 VOID
 Ext2FreeMcb (
index 201607e..8aaeace 100644 (file)
@@ -36,7 +36,7 @@ struct ext3_sb_info {
     int s_addr_per_block_bits;
     int s_desc_per_block_bits;
 
-    struct buffer_head **s_group_desc;
+    ext3_fsblk_t  *s_group_desc;
 
 #if 0
     unsigned long s_frag_size; /* Size of a fragment in bytes */
index a4f0638..fedf491 100644 (file)
@@ -252,6 +252,6 @@ int ext4_ext_get_blocks(void *icb, handle_t *handle, struct inode *inode, ext4_f
                        unsigned long max_blocks, struct buffer_head *bh_result,
                        int create, int flags);
 int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode);
-int ext4_ext_remove_space(void *icb, struct inode *inode, unsigned long start);
+int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start);
 
 #endif /* _LINUX_EXT4_EXT */
index 69aecbd..52a8b3d 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/atomic.h>
+#include <linux/rbtree.h>
 
 //
 // kdev
@@ -74,6 +75,25 @@ struct super_block {
     void               *s_fs_info;
 };
 
+struct xattr_entry {
+    char            xe_name_index;
+    char           *xe_name;
+    char            xe_name_len;
+    char           *xe_value;
+    int            xe_value_size;
+    int            xe_value_buf_size;
+    struct rb_node xe_node;
+};
+
+#define XATTR_FLAG_DIRTY  0x1
+#define XATTR_FLAG_LOADED 0x2
+
+struct xattr_handle {
+    int            xh_flags;
+    int            xh_total_size;
+    struct rb_root xh_root;  
+};
+
 struct inode {
     __u32               i_ino;              /* inode number */
     loff_t                         i_size;             /* size */
@@ -94,6 +114,9 @@ struct inode {
 
     struct super_block *i_sb;               /* super_block */
     void               *i_priv;             /* EXT2_MCB */
+
+    __u16               i_extra_isize;      /* extra fields' size */
+    __u64               i_file_acl;
 };
 
 //
@@ -153,4 +176,4 @@ void iget(struct inode *inode);
 void iput(struct inode *inode);
 ULONGLONG bmap(struct inode *i, ULONGLONG b);
 
-#endif /*_LINUX_FS_INCLUDE_*/
\ No newline at end of file
+#endif /*_LINUX_FS_INCLUDE_*/
index 60badad..f61263b 100644 (file)
 
 #define journal_oom_retry 1
 
+#define jbdlock_t FAST_MUTEX
+
+static inline void jbd_lock_init(jbdlock_t *lock)
+{
+    ExInitializeFastMutex(lock);
+}
+
+static inline void jbd_lock(jbdlock_t *lock)
+{
+    ExAcquireFastMutex(lock);
+}
+
+static inline void jbd_unlock(jbdlock_t *lock)
+{
+    ExReleaseFastMutex(lock);
+}
+
+static inline int assert_jbd_locked(jbdlock_t *lock)
+{
+    int rc = 1;
+
+    if (ExTryToAcquireFastMutex(lock)) {
+        ExReleaseFastMutex(lock);
+        rc = 0;
+    }
+
+    return rc;
+}
+
+
 /*
  * Define JBD_PARANIOD_IOFAIL to cause a kernel BUG() if ext3 finds
  * certain classes of error which can occur due to failed IOs.  Under
@@ -539,7 +569,7 @@ struct transaction_s
     /*
      * Protects info related to handles
      */
-    spinlock_t         t_handle_lock;
+    jbdlock_t          t_handle_lock;
 
     /*
      * Number of outstanding updates running on this transaction
@@ -657,7 +687,7 @@ struct journal_s
     /*
      * Protect the various scalars in the journal
      */
-    spinlock_t         j_state_lock;
+    jbdlock_t          j_state_lock;
 
     /*
      * Number of processes waiting to create a barrier lock [j_state_lock]
@@ -754,7 +784,7 @@ struct journal_s
     /*
      * Protects the buffer lists and internal buffer state.
      */
-    spinlock_t         j_list_lock;
+    jbdlock_t          j_list_lock;
 
     /* Optional inode where we store the journal.  If present, all */
     /* journal block numbers are mapped into this inode via */
@@ -812,7 +842,7 @@ struct journal_s
      * The revoke table: maintains the list of revoked blocks in the
      * current transaction.  [j_revoke_lock]
      */
-    spinlock_t         j_revoke_lock;
+    jbdlock_t          j_revoke_lock;
     struct jbd_revoke_table_s *j_revoke;
     struct jbd_revoke_table_s *j_revoke_table[2];
 
index c0f0d65..ac35b5a 100644 (file)
@@ -4,7 +4,7 @@
  * FILE:             Modules.h
  * PURPOSE:          Header file: nls structures & linux kernel ...
  * PROGRAMMER:       Matt Wu <mattwu@163.com>
- * HOMEPAGE:         http://ext2.yeah.net
+ * HOMEPAGE:         http://www.ext2fsd.com
  * UPDATE HISTORY:
  */
 
@@ -15,9 +15,9 @@
 
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/rbtree.h>
 #include <linux/fs.h>
 #include <linux/log2.h>
-#include <linux/rbtree.h>
 
 #if _WIN32_WINNT <= 0x500
 #define _WIN2K_TARGET_ 1
@@ -712,7 +712,7 @@ struct buffer_head {
     unsigned long b_state;                         /* buffer state bitmap (see above) */
     struct page *b_page;                    /* the page this bh is mapped to */
     PMDL         b_mdl;                     /* MDL of the locked buffer */
-    void       *b_bcb;                     /* BCB of the buffer */
+    void           *b_bcb;                     /* BCB of the buffer */
 
     // kdev_t b_dev;                        /* device (B_FREE = free) */
     struct block_device *b_bdev;            /* block device object */
@@ -940,6 +940,14 @@ static inline void brelse(struct buffer_head *bh)
         __brelse(bh);
 }
 
+static inline void fini_bh(struct buffer_head **bh)
+{
+    if (bh && *bh) {
+        brelse(*bh);
+        *bh = NULL;
+    }
+}
+
 static inline void bforget(struct buffer_head *bh)
 {
     if (bh)
index 0822acc..39b9039 100644 (file)
@@ -94,8 +94,6 @@ static inline struct page * rb_insert_page_cache(struct inode * inode,
 #ifndef        _LINUX_RBTREE_H
 #define        _LINUX_RBTREE_H
 
-#include <linux/module.h>
-
 struct rb_node
 {
     ULONG_PTR       rb_parent_color;
diff --git a/reactos/drivers/filesystems/ext2/src/access.c b/reactos/drivers/filesystems/ext2/src/access.c
new file mode 100644 (file)
index 0000000..03ec404
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * COPYRIGHT:        See COPYRIGHT.TXT
+ * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
+ * FILE:             access.c
+ * PROGRAMMER:       Matt Wu <mattwu@163.com>
+ * HOMEPAGE:         http://www.ext2fsd.com
+ * UPDATE HISTORY:
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "ext2fs.h"
+
+/* GLOBALS ***************************************************************/
+
+extern PEXT2_GLOBAL Ext2Global;
+
+/* DEFINITIONS *************************************************************/
+
+int Ext2CheckInodeAccess(PEXT2_VCB Vcb, struct inode *in, int attempt)
+{
+    int granted = 0;
+
+    uid_t uid = Vcb->uid;
+    gid_t gid = Vcb->gid;
+
+    if (IsFlagOn(Vcb->Flags, VCB_USER_EIDS)) {
+        uid = Vcb->euid;
+        gid = Vcb->egid;
+    }
+
+    if (!uid || uid == in->i_uid) {
+        /* grant all access for inode owner or root */
+        granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
+    } else if (gid == in->i_gid) {
+        if (Ext2IsGroupReadOnly(in->i_mode))
+            granted = Ext2FileCanRead | Ext2FileCanExecute;
+        else if (Ext2IsGroupWritable(in->i_mode))
+            granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
+    } else {
+        if (Ext2IsOtherReadOnly(in->i_mode))
+            granted = Ext2FileCanRead | Ext2FileCanExecute;
+        else if (Ext2IsOtherWritable(in->i_mode))
+            granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
+
+    }
+
+    return IsFlagOn(granted, attempt);
+}
+
+int Ext2CheckFileAccess(PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt)
+{
+    return Ext2CheckInodeAccess(Vcb, &Mcb->Inode, attempt);
+}
index 2c04b8d..bc20461 100644 (file)
@@ -22,12 +22,12 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     PDEVICE_OBJECT  DeviceObject;
     NTSTATUS        Status = STATUS_SUCCESS;
-    PEXT2_VCB       Vcb;
+    PEXT2_VCB       Vcb = NULL;
     PFILE_OBJECT    FileObject;
-    PEXT2_FCB       Fcb;
-    PEXT2_CCB       Ccb;
-    PIRP            Irp;
-    PEXT2_MCB       Mcb;
+    PEXT2_FCB       Fcb = NULL;
+    PEXT2_CCB       Ccb = NULL;
+    PIRP            Irp = NULL;
+    PEXT2_MCB       Mcb = NULL;
 
 
     BOOLEAN         VcbResourceAcquired = FALSE;
@@ -75,7 +75,7 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
         VcbResourceAcquired =
             ExAcquireResourceExclusiveLite(
                 &Vcb->MainResource,
-                IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
+                TRUE
             );
 
         if (Fcb->Identifier.Type == EXT2VCB) {
@@ -143,7 +143,7 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
         FcbResourceAcquired =
             ExAcquireResourceExclusiveLite(
                 &Fcb->MainResource,
-                IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
+                TRUE
             );
 
         ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
@@ -237,8 +237,14 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
                     if (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart) {
                         if (!INODE_HAS_EXTENT(Fcb->Inode)) {
                         #if EXT2_PRE_ALLOCATION_SUPPORT
-                            CcZeroData(FileObject, &Fcb->Header.ValidDataLength,
-                                       &Fcb->Header.AllocationSize, TRUE);
+                            _SEH2_TRY {
+                                CcZeroData( FileObject,
+                                           &Fcb->Header.ValidDataLength,
+                                           &Fcb->Header.AllocationSize,
+                                           TRUE);
+                            } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+                                DbgBreak();
+                            } _SEH2_END;
                         #endif
                         }
                     }
@@ -315,7 +321,7 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
                 FcbResourceAcquired =
                     ExAcquireResourceExclusiveLite(
                         &Fcb->MainResource,
-                        IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
+                        TRUE
                     );
 
                 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
@@ -329,7 +335,7 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
         if (!IsDirectory(Fcb)) {
 
             if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
-                    (Fcb->NonCachedOpenCount + 1 == Fcb->ReferenceCount) &&
+                    (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) &&
                     (Fcb->SectionObject.DataSectionObject != NULL)) {
 
                 if (!IsVcbReadOnly(Vcb)) {
@@ -337,14 +343,17 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
                     ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
                 }
 
-                if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
-                    ExReleaseResourceLite(&(Fcb->PagingIoResource));
-                }
+                /* purge cache if all remaining openings are non-cached */
+                if (Fcb->NonCachedOpenCount > 0) {
+                    if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
+                        ExReleaseResourceLite(&(Fcb->PagingIoResource));
+                    }
 
-                CcPurgeCacheSection( &Fcb->SectionObject,
-                                     NULL,
-                                     0,
-                                     FALSE );
+                    CcPurgeCacheSection( &Fcb->SectionObject,
+                                         NULL,
+                                         0,
+                                         FALSE );
+                }
             }
 
             CcUninitializeCacheMap(FileObject, NULL, NULL);
index de2d687..6403b5c 100644 (file)
@@ -28,11 +28,11 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
     PDEVICE_OBJECT  DeviceObject;
     NTSTATUS        Status = STATUS_SUCCESS;
     PEXT2_VCB       Vcb = NULL;
-    BOOLEAN         VcbResourceAcquired = FALSE;
     PFILE_OBJECT    FileObject;
-    PEXT2_FCB       Fcb;
+    PEXT2_FCB       Fcb = NULL;
+    PEXT2_CCB       Ccb = NULL;
+    BOOLEAN         VcbResourceAcquired = FALSE;
     BOOLEAN         FcbResourceAcquired = FALSE;
-    PEXT2_CCB       Ccb;
     BOOLEAN         bDeleteVcb = FALSE;
     BOOLEAN         bBeingClosed = FALSE;
     BOOLEAN         bSkipLeave = FALSE;
@@ -57,7 +57,7 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
 
         if (!ExAcquireResourceExclusiveLite(
                     &Vcb->MainResource,
-                    IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+                    TRUE )) {
             DEBUG(DL_INF, ("Ext2Close: PENDING ... Vcb: %xh/%xh\n",
                            Vcb->OpenHandleCount, Vcb->ReferenceCount));
 
@@ -118,7 +118,7 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
 
         if (!ExAcquireResourceExclusiveLite(
                     &Fcb->MainResource,
-                    IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+                    TRUE )) {
             Status = STATUS_PENDING;
             _SEH2_LEAVE;
         }
@@ -178,7 +178,7 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
 
         if (NT_SUCCESS(Status) && Vcb != NULL && IsVcbInited(Vcb)) {
             /* for Ext2Fsd driver open/close, Vcb is NULL */
-            if ((!bBeingClosed) && (Vcb->ReferenceCount == 0)&&
+            if ((!bBeingClosed) && (Vcb->ReferenceCount == 0) &&
                 (!IsMounted(Vcb) || IsDispending(Vcb))) {
                 bDeleteVcb = TRUE;
             }
index 43703ea..6ef28f7 100644 (file)
@@ -68,7 +68,7 @@ Ext2FollowLink (
     IN PEXT2_VCB            Vcb,
     IN PEXT2_MCB            Parent,
     IN PEXT2_MCB            Mcb,
-    IN USHORT               Linkdep
+    IN ULONG                Linkdep
 )
 {
     NTSTATUS        Status = STATUS_LINK_FAILED;
@@ -88,7 +88,7 @@ Ext2FollowLink (
 
         /* exit if we jump into a possible symlink forever loop */
         if ((Linkdep + 1) > EXT2_MAX_NESTED_LINKS ||
-                IoGetRemainingStackSize() < 1024) {
+            IoGetRemainingStackSize() < 1024) {
             _SEH2_LEAVE;
         }
 
@@ -113,14 +113,12 @@ Ext2FollowLink (
             bOemBuffer = TRUE;
             RtlZeroMemory(OemName.Buffer, OemName.MaximumLength);
 
-            Status = Ext2ReadInode(
+            Status = Ext2ReadSymlink(
                          IrpContext,
                          Vcb,
                          Mcb,
-                         (ULONGLONG)0,
                          OemName.Buffer,
                          (ULONG)(Mcb->Inode.i_size),
-                         FALSE,
                          NULL);
             if (!NT_SUCCESS(Status)) {
                 _SEH2_LEAVE;
@@ -170,9 +168,9 @@ Ext2FollowLink (
         }
 
         if (Target == NULL /* link target doesn't exist */      ||
-                Target == Mcb  /* symlink points to itself */       ||
-                IsMcbSpecialFile(Target) /* target not resolved*/   ||
-                IsFileDeleted(Target)  /* target deleted */         ) {
+            Target == Mcb  /* symlink points to itself */       ||
+            IsMcbSpecialFile(Target) /* target not resolved*/   ||
+            IsFileDeleted(Target)  /* target deleted */         ) {
 
             if (Target) {
                 ASSERT(Target->Refercount > 0);
@@ -180,7 +178,6 @@ Ext2FollowLink (
             }
             ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
             SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
-            Mcb->FileAttr = FILE_ATTRIBUTE_NORMAL;
             Mcb->Target = NULL;
 
         } else if (IsMcbSymLink(Target)) {
@@ -194,15 +191,18 @@ Ext2FollowLink (
             SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
             ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
             ASSERT(Mcb->Target->Refercount > 0);
-            Mcb->FileAttr = Target->FileAttr;
-
+            
         } else {
 
             Mcb->Target = Target;
             SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
             ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
             ASSERT(Mcb->Target->Refercount > 0);
-            Mcb->FileAttr = Target->FileAttr;
+        }
+
+        /* add directory flag to file attribute */
+        if (Mcb->Target && IsMcbDirectory(Mcb->Target)) {
+            Mcb->FileAttr |= FILE_ATTRIBUTE_DIRECTORY;
         }
 
     } _SEH2_FINALLY {
@@ -275,7 +275,7 @@ Ext2LookupFile (
     IN PUNICODE_STRING      FullName,
     IN PEXT2_MCB            Parent,
     OUT PEXT2_MCB *         Ext2Mcb,
-    IN USHORT               Linkdep
+    IN ULONG                Linkdep
 )
 {
     NTSTATUS        Status = STATUS_OBJECT_NAME_NOT_FOUND;
@@ -289,12 +289,20 @@ Ext2LookupFile (
     BOOLEAN         bParent = FALSE;
     BOOLEAN         bDirectory = FALSE;
     BOOLEAN         LockAcquired = FALSE;
+    BOOLEAN         bNotFollow = FALSE;
 
     _SEH2_TRY {
 
         ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
         LockAcquired = TRUE;
 
+        bNotFollow = IsFlagOn(Linkdep, EXT2_LOOKUP_NOT_FOLLOW);
+#ifndef __REACTOS__
+        Linkdep = ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+#else
+        ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+#endif
+
         *Ext2Mcb = NULL;
 
         DEBUG(DL_RES, ("Ext2LookupFile: %wZ\n", FullName));
@@ -394,7 +402,7 @@ Ext2LookupFile (
                     Parent = Mcb;
 
                     if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target) &&
-                            (Mcb->Refercount == 1)) {
+                        Mcb->Refercount == 1) {
 
                         ASSERT(Mcb->Target);
                         ASSERT(Mcb->Target->Refercount > 0);
@@ -453,16 +461,18 @@ Ext2LookupFile (
                         }
 
                         /* set inode attribute */
-                        if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Mcb->Inode.i_mode)) {
+                        if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
                             SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_READONLY);
                         }
 
                         if (S_ISDIR(Mcb->Inode.i_mode)) {
                             SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY);
                         } else {
-                            SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
-                            if (!S_ISREG(Mcb->Inode.i_mode) &&
-                                    !S_ISLNK(Mcb->Inode.i_mode)) {
+                            if (S_ISREG(Mcb->Inode.i_mode)) {
+                                SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
+                            } else if (S_ISLNK(Mcb->Inode.i_mode)) {
+                                SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+                            } else {
                                 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
                             }
                         }
@@ -484,7 +494,7 @@ Ext2LookupFile (
                         Mcb->ChangeTime = Ext2NtTime(Mcb->Inode.i_mtime);
 
                         /* process symlink */
-                        if (S_ISLNK(Mcb->Inode.i_mode)) {
+                        if (S_ISLNK(Mcb->Inode.i_mode) && !bNotFollow) {
                             Ext2FollowLink( IrpContext,
                                             Vcb,
                                             Parent,
@@ -616,7 +626,7 @@ Ext2ScanDir (
         Ext2DerefMcb(Parent);
 
         if (bh)
-            brelse(bh);
+            __brelse(bh);
 
         if (!NT_SUCCESS(Status)) {
             if (de)
@@ -659,7 +669,7 @@ NTSTATUS Ext2AddDotEntries(struct ext2_icb *icb, struct inode *dir,
 
 errorout:
     if (bh)
-        brelse (bh);
+        __brelse (bh);
 
     return Ext2WinntError(rc);
 }
@@ -708,9 +718,11 @@ Ext2CreateFile(
     BOOLEAN             DeleteOnClose;
     BOOLEAN             TemporaryFile;
     BOOLEAN             CaseSensitive;
+    BOOLEAN             OpenReparsePoint;
 
     ACCESS_MASK         DesiredAccess;
     ULONG               ShareAccess;
+    ULONG               CcbFlags = 0;
 
     RtlZeroMemory(&FileName, sizeof(UNICODE_STRING));
 
@@ -728,6 +740,9 @@ Ext2CreateFile(
     NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
     DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE);
 
+    /* Try to open reparse point (symlink) itself ? */
+    OpenReparsePoint = IsFlagOn(Options, FILE_OPEN_REPARSE_POINT);
+
     CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE);
 
     TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes,
@@ -843,7 +858,8 @@ Ext2CreateFile(
                      &FileName,
                      ParentMcb,
                      &Mcb,
-                     0 );
+                     0  /* always follow link */
+                    );
 McbExisting:
 
         if (!NT_SUCCESS(Status)) {
@@ -964,7 +980,7 @@ Dissecting:
                     _SEH2_LEAVE;
                 }
 
-                if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(ParentFcb->Mcb->Inode.i_mode)) {
+                if (!Ext2CheckFileAccess(Vcb, ParentMcb, Ext2FileCanWrite)) {
                     Status = STATUS_ACCESS_DENIED;
                     _SEH2_LEAVE;
                 }
@@ -1104,7 +1120,7 @@ Dissecting:
             if (IsMcbDirectory(Mcb)) {
 
                 if ((CreateDisposition != FILE_OPEN) &&
-                        (CreateDisposition != FILE_OPEN_IF)) {
+                    (CreateDisposition != FILE_OPEN_IF)) {
 
                     Status = STATUS_OBJECT_NAME_COLLISION;
                     Ext2DerefMcb(Mcb);
@@ -1147,7 +1163,11 @@ Openit:
 
             /* refer it's target if it's a symlink, so both refered */
             if (IsMcbSymLink(Mcb)) {
-                if (IsFileDeleted(Mcb->Target)) {
+
+                if (OpenReparsePoint) {
+                    /* set Ccb flag */
+                    CcbFlags = CCB_OPEN_REPARSE_POINT;
+                } else if (IsFileDeleted(Mcb->Target)) {
                     DbgBreak();
                     SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
                     ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
@@ -1162,7 +1182,12 @@ Openit:
             }
 
             // Check readonly flag
-            if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Mcb->Inode.i_mode)) {
+            if (BooleanFlagOn(DesiredAccess,  FILE_GENERIC_READ) &&
+                !Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanRead)) {
+                Status = STATUS_ACCESS_DENIED;
+                _SEH2_LEAVE;
+            }
+            if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
                 if (BooleanFlagOn(DesiredAccess,  FILE_WRITE_DATA | FILE_APPEND_DATA |
                                   FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD)) {
                     Status = STATUS_ACCESS_DENIED;
@@ -1398,7 +1423,7 @@ Openit:
                                   &(Fcb->ShareAccess) );
             }
 
-            Ccb = Ext2AllocateCcb(SymLink);
+            Ccb = Ext2AllocateCcb(CcbFlags, SymLink);
             if (!Ccb) {
                 Status = STATUS_INSUFFICIENT_RESOURCES;
                 DbgBreak();
@@ -1684,7 +1709,7 @@ Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
         return STATUS_SHARING_VIOLATION;
     }
 
-    Ccb = Ext2AllocateCcb(NULL);
+    Ccb = Ext2AllocateCcb(0, NULL);
     if (Ccb == NULL) {
         Status = STATUS_INSUFFICIENT_RESOURCES;
         goto errorout;
@@ -1869,9 +1894,9 @@ Ext2CreateInode(
     Inode.i_sb = &Vcb->sb;
     Inode.i_ino = iNo;
     Inode.i_ctime = Inode.i_mtime =
-                        Inode.i_atime = Ext2LinuxTime(SysTime);
-    Inode.i_uid = Parent->Inode->i_uid;
-    Inode.i_gid = Parent->Inode->i_gid;
+    Inode.i_atime = Ext2LinuxTime(SysTime);
+    Inode.i_uid = Vcb->uid;
+    Inode.i_gid = Vcb->gid;
     Inode.i_generation = Parent->Inode->i_generation;
     Inode.i_mode = S_IPERMISSION_MASK &
                    Parent->Inode->i_mode;
@@ -1887,6 +1912,11 @@ Ext2CreateInode(
     /* Force using extent */
     if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
         Inode.i_flags |= EXT2_EXTENTS_FL;
+        ext4_ext_tree_init(IrpContext, NULL, &Inode);
+        /* ext4_ext_tree_init will save inode body */
+    } else {
+        /* save inode body to cache */
+        Ext2SaveInode(IrpContext, Vcb, &Inode);
     }
 
     /* add new entry to its parent */
index 881a632..f15b415 100644 (file)
@@ -2654,6 +2654,7 @@ Ext2FreePool(
     NumberOfBytes = Data[0];
     if (Data[1] != NumberOfBytes + 0x20) {
         DbgBreak();
+        return;
     }
     for (i=0x08; i < 0x10; i++) {
         if (Buffer[i] != 'S') {
@@ -2664,6 +2665,7 @@ Ext2FreePool(
     for (i=0; i < 0x10; i++) {
         if (Buffer[i + NumberOfBytes + 0x10] != 'E') {
             DbgBreak();
+            return;
         }
         Buffer[i + NumberOfBytes + 0x10] = '-';
     }
index 1950649..b76385d 100644 (file)
@@ -96,6 +96,8 @@ Ext2ProcessEntry(
     LONGLONG AllocationSize;
     ULONG   FileAttributes = 0;
 
+    BOOLEAN IsEntrySymlink = FALSE;
+
     *EntrySize = 0;
     NameLength = pName->Length;
     ASSERT((UsedLength & 7) == 0);
@@ -120,7 +122,12 @@ Ext2ProcessEntry(
     DEBUG(DL_CP, ("Ext2ProcessDirEntry: %wZ in %wZ\n", pName, &Dcb->Mcb->FullName ));
 
     Mcb = Ext2SearchMcb(Vcb, Dcb->Mcb, pName);
-    if (NULL == Mcb) {
+    if (NULL != Mcb) {
+        if (S_ISLNK(Mcb->Inode.i_mode) && NULL == Mcb->Target) {
+            Ext2FollowLink( IrpContext, Vcb, Dcb->Mcb, Mcb, 0);
+        }
+
+    } else {
 
         Inode.i_ino = in;
         Inode.i_sb = &Vcb->sb;
@@ -136,7 +143,7 @@ Ext2ProcessEntry(
         } else if (S_ISLNK(Inode.i_mode)) {
             DEBUG(DL_RES, ("Ext2ProcessDirEntry: SymLink: %wZ\\%wZ\n",
                            &Dcb->Mcb->FullName, pName));
-            Ext2LookupFile(IrpContext, Vcb, pName, Dcb->Mcb, &Mcb, 0);
+            Ext2LookupFile(IrpContext, Vcb, pName, Dcb->Mcb, &Mcb,0);
 
             if (Mcb && IsMcbSpecialFile(Mcb)) {
                 Ext2DerefMcb(Mcb);
@@ -156,6 +163,7 @@ Ext2ProcessEntry(
             ASSERT(!IsMcbSymLink(Target));
             if (IsMcbDirectory(Target)) {
                 FileSize = 0;
+                FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
             } else {
                 FileSize = Target->Inode.i_size;
             }
@@ -171,6 +179,10 @@ Ext2ProcessEntry(
             }
         }
 
+        if (IsInodeSymLink(&Mcb->Inode)) {
+            IsEntrySymlink = TRUE;
+        }
+
     } else {
 
         if (S_ISDIR(Inode.i_mode)) {
@@ -181,11 +193,14 @@ Ext2ProcessEntry(
 
         if (S_ISDIR(Inode.i_mode)) {
             FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
+        } else if (S_ISLNK(Inode.i_mode)) {
+            FileAttributes = FILE_ATTRIBUTE_REPARSE_POINT;
+            IsEntrySymlink = TRUE;
         } else {
             FileAttributes = FILE_ATTRIBUTE_NORMAL;
         }
 
-        if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Inode.i_mode)) {
+        if (!Ext2CheckInodeAccess(Vcb, &Inode, Ext2FileCanWrite)) {
             SetFlag(FileAttributes, FILE_ATTRIBUTE_READONLY);
         }
     }
@@ -254,8 +269,14 @@ Ext2ProcessEntry(
 
         if (FIF) {
             FIF->FileId.QuadPart = (LONGLONG) in;
+            if (IsEntrySymlink) {
+                FIF->EaSize = IO_REPARSE_TAG_SYMLINK;
+            }
             RtlCopyMemory(&FIF->FileName[0], &pName->Buffer[0], NameLength);
         } else if (FFI) {
+            if (IsEntrySymlink) {
+                FFI->EaSize = IO_REPARSE_TAG_SYMLINK;
+            }
             RtlCopyMemory(&FFI->FileName[0], &pName->Buffer[0], NameLength);
         } else {
             RtlCopyMemory(&FDI->FileName[0], &pName->Buffer[0], NameLength);
@@ -302,6 +323,9 @@ Ext2ProcessEntry(
 
         if (FIB) {
             FIB->FileId.QuadPart = (LONGLONG)in;
+            if (IsEntrySymlink) {
+                FIB->EaSize = IO_REPARSE_TAG_SYMLINK;
+            }
             RtlCopyMemory(&FIB->FileName[0], &pName->Buffer[0], NameLength);
         } else {
             RtlCopyMemory(&FBI->FileName[0], &pName->Buffer[0], NameLength);
@@ -502,13 +526,13 @@ Ext2QueryDirectory (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     PDEVICE_OBJECT          DeviceObject;
     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
-    PEXT2_VCB               Vcb;
-    PFILE_OBJECT            FileObject;
-    PEXT2_FCB               Fcb;
-    PEXT2_MCB               Mcb;
-    PEXT2_CCB               Ccb;
-    PIRP                    Irp;
-    PIO_STACK_LOCATION      IoStackLocation;
+    PEXT2_VCB               Vcb = NULL;
+    PFILE_OBJECT            FileObject = NULL;
+    PEXT2_FCB               Fcb = NULL;
+    PEXT2_MCB               Mcb = NULL;
+    PEXT2_CCB               Ccb = NULL;
+    PIRP                    Irp = NULL;
+    PIO_STACK_LOCATION      IoStackLocation = NULL;
 
     ULONG                   Length;
     ULONG                   FileIndex;
@@ -1009,12 +1033,12 @@ Ext2NotifyChangeDirectory (
     PDEVICE_OBJECT      DeviceObject;
     BOOLEAN             CompleteRequest = TRUE;
     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
-    PEXT2_VCB           Vcb;
-    PFILE_OBJECT        FileObject;
-    PEXT2_FCB           Fcb;
-    PEXT2_CCB           Ccb;
-    PIRP                Irp;
+    PEXT2_VCB           Vcb = NULL;
+    PEXT2_FCB           Fcb = NULL;
+    PEXT2_CCB           Ccb = NULL;
+    PIRP                Irp = NULL;
     PIO_STACK_LOCATION  IrpSp;
+    PFILE_OBJECT        FileObject;
     ULONG               CompletionFilter;
     BOOLEAN             WatchTree;
 
@@ -1243,4 +1267,4 @@ Ext2IsDirectoryEmpty (
     }
 
     return !!ext3_is_dir_empty(IrpContext, &Mcb->Inode);
-}
\ No newline at end of file
+}
index 55221e6..2ae5b0f 100644 (file)
@@ -3,7 +3,7 @@
  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
  * FILE:             generic.c
  * PROGRAMMER:       Matt Wu <mattwu@163.com>
- * HOMEPAGE:         http://ext2.yeah.net
+ * HOMEPAGE:         http://www.ext2fsd.com
  * UPDATE HISTORY:
  */
 
@@ -132,15 +132,15 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb)
 {
     struct super_block  *sb = &Vcb->sb;
     struct ext3_sb_info *sbi = &Vcb->sbi;
+    ext3_fsblk_t sb_block = 1;
     unsigned long i;
-    ext3_fsblk_t block, sb_block = 1;
 
     if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
         sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
     }
 
     if (NULL == sbi->s_group_desc) {
-        sbi->s_group_desc = kzalloc(sbi->s_gdb_count * sizeof(void *),
+        sbi->s_group_desc = kzalloc(sbi->s_gdb_count * sizeof(ext3_fsblk_t),
                                     GFP_KERNEL);
     }
     if (sbi->s_group_desc == NULL) {
@@ -149,10 +149,7 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb)
     }
 
     for (i = 0; i < sbi->s_gdb_count; i++) {
-        block = descriptor_loc(sb, sb_block, i);
-        if (sbi->s_group_desc[i])
-            continue;
-        sbi->s_group_desc[i] = sb_bread(sb, block);
+        sbi->s_group_desc[i] =  descriptor_loc(sb, sb_block, i);
         if (!sbi->s_group_desc[i]) {
             DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i));
             return FALSE;
@@ -167,28 +164,19 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb)
     return TRUE;
 }
 
+
 VOID
-Ext2PutGroup(IN PEXT2_VCB Vcb)
+Ext2DropGroup(IN PEXT2_VCB Vcb)
 {
     struct ext3_sb_info *sbi = &Vcb->sbi;
     unsigned long i;
 
-    ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
     if (NULL == sbi->s_group_desc) {
-        ExReleaseResourceLite(&Vcb->MetaLock);
         return;
     }
 
-    for (i = 0; i < sbi->s_gdb_count; i++) {
-        if (sbi->s_group_desc[i]) {
-            brelse(sbi->s_group_desc[i]);
-            sbi->s_group_desc[i] = NULL;
-        }
-    }
-
     kfree(sbi->s_group_desc);
     sbi->s_group_desc = NULL;
-    ExReleaseResourceLite(&Vcb->MetaLock);
 }
 
 BOOLEAN
@@ -198,22 +186,17 @@ Ext2SaveGroup(
     IN ULONG                Group
 )
 {
-    struct ext4_group_desc *desc;
-    struct buffer_head  *bh = NULL;
+    struct ext4_group_desc *gd;
+    struct buffer_head     *gb = NULL;
     unsigned long i;
 
-    ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
-    desc = ext4_get_group_desc(&Vcb->sb, Group, &bh);
-    if (bh)
-        get_bh(bh);
-    ExReleaseResourceLite(&Vcb->MetaLock);
-
-    if (!bh)
+    gd = ext4_get_group_desc(&Vcb->sb, Group, &gb);
+    if (!gd)
         return 0;
 
-    desc->bg_checksum = ext4_group_desc_csum(&Vcb->sbi, Group, desc);
-    mark_buffer_dirty(bh);
-    __brelse(bh);
+    gd->bg_checksum = ext4_group_desc_csum(&Vcb->sbi, Group, gd);
+    mark_buffer_dirty(gb);
+    fini_bh(&gb);
 
     return TRUE;
 }
@@ -236,6 +219,7 @@ Ext2GetInodeLba (
 )
 {
     PEXT2_GROUP_DESC gd;
+    struct buffer_head *bh = NULL;
     ext4_fsblk_t loc;
     int group;
 
@@ -246,8 +230,8 @@ Ext2GetInodeLba (
     }
 
     group = (inode - 1) / INODES_PER_GROUP ;
-    gd = ext4_get_group_desc(&Vcb->sb, group, NULL);
-    if (!gd) {
+    gd = ext4_get_group_desc(&Vcb->sb, group, &bh);
+    if (!bh) {
         *offset = 0;
         DbgBreak();
         return FALSE;
@@ -257,6 +241,7 @@ Ext2GetInodeLba (
     loc = loc + ((inode - 1) % INODES_PER_GROUP) * Vcb->InodeSize;
 
     *offset = loc;
+    __brelse(bh);
 
     return TRUE;
 }
@@ -273,11 +258,14 @@ void Ext2DecodeInode(struct inode *dst, struct ext3_inode *src)
     if (S_ISREG(src->i_mode)) {
         dst->i_size |= (loff_t)src->i_size_high << 32;
     }
+    dst->i_file_acl = src->i_file_acl_lo;
+    dst->i_file_acl |= (ext4_fsblk_t)src->osd2.linux2.l_i_file_acl_high << 32;
     dst->i_atime = src->i_atime;
     dst->i_ctime = src->i_ctime;
     dst->i_mtime = src->i_mtime;
     dst->i_dtime = src->i_dtime;
     dst->i_blocks = ext3_inode_blocks(src, dst);
+    dst->i_extra_isize = src->i_extra_isize;
     memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
 }
 
@@ -293,10 +281,13 @@ void Ext2EncodeInode(struct ext3_inode *dst,  struct inode *src)
     if (S_ISREG(src->i_mode)) {
         dst->i_size_high = (__u32)(src->i_size >> 32);
     }
+    dst->i_file_acl_lo = (__u32)src->i_file_acl;
+    dst->osd2.linux2.l_i_file_acl_high |= (__u16)(src->i_file_acl >> 32);
     dst->i_atime = src->i_atime;
     dst->i_ctime = src->i_ctime;
     dst->i_mtime = src->i_mtime;
     dst->i_dtime = src->i_dtime;
+    dst->i_extra_isize = src->i_extra_isize;
     ASSERT(src->i_sb);
     ext3_inode_blocks_set(dst, src);
     memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
@@ -584,8 +575,9 @@ Ext2NewBlock(
 )
 {
     struct super_block      *sb = &Vcb->sb;
-    PEXT2_GROUP_DESC        group_desc;
-    struct buffer_head*     bh = NULL;
+    PEXT2_GROUP_DESC        gd;
+    struct buffer_head     *gb = NULL;
+    struct buffer_head     *bh = NULL;
     ext4_fsblk_t            bitmap_blk;
 
     RTL_BITMAP              BlockBitmap;
@@ -617,31 +609,32 @@ Ext2NewBlock(
 
 Again:
 
-    if (bh) {
-        __brelse(bh);
-        bh = NULL;
-    }
+    if (bh)
+        fini_bh(&bh);
+
+    if (gb)
+        fini_bh(&gb);
 
-    group_desc = ext4_get_group_desc(sb, Group, NULL);
-    if (!group_desc) {
+    gd = ext4_get_group_desc(sb, Group, &gb);
+    if (!gd) {
         DbgBreak();
         Status = STATUS_INSUFFICIENT_RESOURCES;
         goto errorout;
     }
 
-    bitmap_blk = ext4_block_bitmap(sb, group_desc);
+    bitmap_blk = ext4_block_bitmap(sb, gd);
 
-    if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+    if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
         bh = sb_getblk_zero(sb, bitmap_blk);
         if (!bh) {
             DbgBreak();
             Status = STATUS_INSUFFICIENT_RESOURCES;
             goto errorout;
         }
-        group_desc->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, group_desc);
-        ext4_init_block_bitmap(sb, bh, Group, group_desc);
+        gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
+        ext4_init_block_bitmap(sb, bh, Group, gd);
         set_buffer_uptodate(bh);
-        group_desc->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
+        gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
         Ext2SaveGroup(IrpContext, Vcb, Group);
     } else {
         bh = sb_getblk(sb, bitmap_blk);
@@ -661,7 +654,7 @@ Again:
            }
     }
 
-    if (ext4_free_blks_count(sb, group_desc)) {
+    if (ext4_free_blks_count(sb, gd)) {
 
         if (Group == Vcb->sbi.s_groups_count - 1) {
 
@@ -696,7 +689,7 @@ Again:
                 RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
 
                 /* no blocks found: set bg_free_blocks_count to 0 */
-                ext4_free_blks_set(sb, group_desc, 0);
+                ext4_free_blks_set(sb, gd, 0);
                 Ext2SaveGroup(IrpContext, Vcb, Group);
 
                 /* will try next group */
@@ -732,7 +725,7 @@ Again:
         mark_buffer_dirty(bh);
 
         /* update group description */
-        ext4_free_blks_set(sb, group_desc, RtlNumberOfClearBits(&BlockBitmap));
+        ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
         Ext2SaveGroup(IrpContext, Vcb, Group);
 
         /* update Vcb free blocks */
@@ -746,9 +739,9 @@ Again:
             goto Again;
         }
 
-        if (ext4_block_bitmap(sb, group_desc) == *Block ||
-            ext4_inode_bitmap(sb, group_desc) == *Block ||
-            ext4_inode_table(sb, group_desc)  == *Block ) {
+        if (ext4_block_bitmap(sb, gd) == *Block ||
+            ext4_inode_bitmap(sb, gd) == *Block ||
+            ext4_inode_table(sb,  gd)  == *Block ) {
             DbgBreak();
             dwHint = 0;
             goto Again;
@@ -772,7 +765,10 @@ errorout:
     ExReleaseResourceLite(&Vcb->MetaLock);
 
     if (bh)
-        __brelse(bh);
+        fini_bh(&bh);
+
+    if (gb)
+        fini_bh(&gb);
 
     return Status;
 }
@@ -786,7 +782,8 @@ Ext2FreeBlock(
 )
 {
     struct super_block     *sb = &Vcb->sb;
-    PEXT2_GROUP_DESC        group_desc;
+    PEXT2_GROUP_DESC        gd;
+    struct buffer_head     *gb = NULL;
     ext4_fsblk_t            bitmap_blk;
 
     RTL_BITMAP      BlockBitmap;
@@ -812,6 +809,9 @@ Ext2FreeBlock(
 
 Again:
 
+    if (gb)
+        fini_bh(&gb);
+
     if ( Block < EXT2_FIRST_DATA_BLOCK ||
          Block >= TOTAL_BLOCKS ||
          Group >= Vcb->sbi.s_groups_count) {
@@ -821,13 +821,13 @@ Again:
 
     } else  {
 
-        group_desc = ext4_get_group_desc(sb, Group, NULL);
-        if (!group_desc) {
+        gd = ext4_get_group_desc(sb, Group, &gb);
+        if (!gd) {
             DbgBreak();
             Status = STATUS_INSUFFICIENT_RESOURCES;
             goto errorout;
         }
-        bitmap_blk = ext4_block_bitmap(sb, group_desc);
+        bitmap_blk = ext4_block_bitmap(sb, gd);
 
         /* check the block is valid or not */
         if (bitmap_blk >= TOTAL_BLOCKS) {
@@ -874,7 +874,7 @@ Again:
         RtlClearBits(&BlockBitmap, Index, Count);
 
         /* update group description table */
-        ext4_free_blks_set(sb, group_desc, RtlNumberOfClearBits(&BlockBitmap));
+        ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
 
         /* indict the cache range is dirty */
         CcSetDirtyPinnedData(BitmapBcb, NULL );
@@ -913,6 +913,9 @@ Again:
 
 errorout:
 
+    if (gb)
+        fini_bh(&gb);
+
     ExReleaseResourceLite(&Vcb->MetaLock);
 
     return Status;
@@ -929,7 +932,8 @@ Ext2NewInode(
 )
 {
     struct super_block     *sb = &Vcb->sb;
-    PEXT2_GROUP_DESC        group_desc;
+    PEXT2_GROUP_DESC        gd;
+    struct buffer_head     *gb = NULL;
     struct buffer_head     *bh = NULL;
     ext4_fsblk_t            bitmap_blk;
 
@@ -951,13 +955,14 @@ Ext2NewInode(
 
 repeat:
 
-    if (bh) {
-        __brelse(bh);
-        bh = NULL;
-    }
+    if (bh)
+        fini_bh(&bh);
+
+    if (gb)
+        fini_bh(&gb);
 
     Group = i = 0;
-    group_desc = NULL;
+    gd = NULL;
 
     if (Type == EXT2_FT_DIR) {
 
@@ -966,31 +971,33 @@ repeat:
         for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
 
             i = (j + GroupHint) % (Vcb->sbi.s_groups_count);
-            group_desc = ext4_get_group_desc(sb, i, NULL);
-            if (!group_desc) {
-                DbgBreak();
+            gd = ext4_get_group_desc(sb, i, &gb);
+            if (!gd) {
+                    DbgBreak();
                 Status = STATUS_INSUFFICIENT_RESOURCES;
                 goto errorout;
             }
 
-            if ((group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) ||
-                (ext4_used_dirs_count(sb, group_desc) << 8 < 
-                 ext4_free_inodes_count(sb, group_desc)) ) {
+            if ((gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) ||
+                (ext4_used_dirs_count(sb, gd) << 8 < 
+                 ext4_free_inodes_count(sb, gd)) ) {
                 Group = i + 1;
                 break;
             }
+            fini_bh(&gb);
         }
 
         if (!Group) {
 
             PEXT2_GROUP_DESC  desc = NULL;
 
-            group_desc = NULL;
+            gd = NULL;
 
             /* get the group with the biggest vacancy */
             for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
 
-                desc = ext4_get_group_desc(sb, j, NULL);
+                struct buffer_head *gt = NULL;
+                desc = ext4_get_group_desc(sb, j, &gt);
                 if (!desc) {
                     DbgBreak();
                     Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -1000,23 +1007,38 @@ repeat:
                 /* return the group if it's not initialized yet */
                 if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
                     Group = j + 1;
-                    group_desc = desc;
+                    gd = desc;
+
+                    if (gb)
+                        fini_bh(&gb);
+                    gb = gt;
+                    gt = NULL;
                     break;
                 }
 
-                if (!group_desc) {
+                if (!gd) {
                     if (ext4_free_inodes_count(sb, desc) > 0) {
                         Group = j + 1;
-                        group_desc = desc;
+                        gd = desc;
+                        if (gb)
+                            fini_bh(&gb);
+                        gb = gt;
+                        gt = NULL;
                     }
                 } else {
                     if (ext4_free_inodes_count(sb, desc) >
-                        ext4_free_inodes_count(sb, group_desc)) {
+                        ext4_free_inodes_count(sb, gd)) {
                         Group = j + 1;
-                        group_desc = desc;
+                        gd = desc;
+                        if (gb)
+                            fini_bh(&gb);
+                        gb = gt;
+                        gt = NULL;
                         break;
                     }
                 }
+                if (gt)
+                    fini_bh(&gt);
             }
         }
 
@@ -1026,20 +1048,23 @@ repeat:
          * Try to place the inode in its parent directory (GroupHint)
          */
 
-        group_desc = ext4_get_group_desc(sb, GroupHint, NULL);
-        if (!group_desc) {
+        gd = ext4_get_group_desc(sb, GroupHint, &gb);
+        if (!gb) {
             DbgBreak();
             Status = STATUS_INSUFFICIENT_RESOURCES;
             goto errorout;
         }
 
-        if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
-            ext4_free_inodes_count(sb, group_desc)) {
+        if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+            ext4_free_inodes_count(sb, gd)) {
 
             Group = GroupHint + 1;
 
         } else {
 
+            /* this group is 100% cocucpied */
+            fini_bh(&gb);
             i = GroupHint;
 
             /*
@@ -1048,19 +1073,22 @@ repeat:
 
             for (j = 1; j < Vcb->sbi.s_groups_count; j <<= 1) {
 
+
                 i = (i + j) % Vcb->sbi.s_groups_count;
-                group_desc = ext4_get_group_desc(sb, i, NULL);
-                if (!group_desc) {
+                gd = ext4_get_group_desc(sb, i, &gb);
+                if (!gd) {
                     DbgBreak();
                     Status = STATUS_INSUFFICIENT_RESOURCES;
                     goto errorout;
                 }
 
-                if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
-                        ext4_free_inodes_count(sb, group_desc)) {
+                if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+                    ext4_free_inodes_count(sb, gd)) {
                     Group = i + 1;
                     break;
                 }
+
+                fini_bh(&gb);  
             }
         }
 
@@ -1072,23 +1100,25 @@ repeat:
             for (j = 2; j < Vcb->sbi.s_groups_count; j++) {
 
                 i = (i + 1) % Vcb->sbi.s_groups_count;
-                group_desc = ext4_get_group_desc(sb, i, NULL);
-                if (!group_desc) {
+                gd = ext4_get_group_desc(sb, i, &gb);
+                if (!gd) {
                     DbgBreak();
                     Status = STATUS_INSUFFICIENT_RESOURCES;
                     goto errorout;
                 }
 
-                if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
-                    ext4_free_inodes_count(sb, group_desc)) {
+                if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+                    ext4_free_inodes_count(sb, gd)) {
                     Group = i + 1;
                     break;
                 }
+
+                fini_bh(&gb);
             }
         }
     }
 
-    if (group_desc == NULL || Group == 0) {
+    if (gd == NULL || Group == 0) {
         goto errorout;
     }
 
@@ -1101,8 +1131,8 @@ repeat:
     /* valid group number starts from 1, not 0 */
     Group -= 1;
 
-    ASSERT(group_desc);
-    bitmap_blk = ext4_inode_bitmap(sb, group_desc);
+    ASSERT(gd);
+    bitmap_blk = ext4_inode_bitmap(sb, gd);
     /* check the block is valid or not */
     if (bitmap_blk == 0 || bitmap_blk >= TOTAL_BLOCKS) {
         DbgBreak();
@@ -1110,17 +1140,17 @@ repeat:
         goto errorout;
     }
 
-    if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+    if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
         bh = sb_getblk_zero(sb, bitmap_blk);
         if (!bh) {
             DbgBreak();
             Status = STATUS_INSUFFICIENT_RESOURCES;
             goto errorout;
         }
-        group_desc->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, group_desc);
-        ext4_init_inode_bitmap(sb, bh, Group, group_desc);
+        gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
+        ext4_init_inode_bitmap(sb, bh, Group, gd);
         set_buffer_uptodate(bh);
-        group_desc->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
+        gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
         Ext2SaveGroup(IrpContext, Vcb, Group);
     } else {
         bh = sb_getblk(sb, bitmap_blk);
@@ -1160,8 +1190,8 @@ repeat:
     if (dwInode == 0xFFFFFFFF || dwInode >= Length) {
 
         RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
-        if (ext4_free_inodes_count(sb, group_desc) > 0) {
-            ext4_free_inodes_set(sb, group_desc, 0);
+        if (ext4_free_inodes_count(sb, gd) > 0) {
+            ext4_free_inodes_set(sb, gd, 0);
             Ext2SaveGroup(IrpContext, Vcb, Group);
         }
         goto repeat;
@@ -1171,8 +1201,8 @@ repeat:
         __u32 count = 0;
 
         /* update unused inodes count */
-        count = ext4_free_inodes_count(sb, group_desc) - 1;
-        ext4_free_inodes_set(sb, group_desc, count);
+        count = ext4_free_inodes_count(sb, gd) - 1;
+        ext4_free_inodes_set(sb, gd, count);
 
         RtlSetBits(&InodeBitmap, dwInode, 1);
 
@@ -1185,8 +1215,8 @@ repeat:
 
             __u32 free;
 
-            if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
-                group_desc->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
+            if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+                gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
                 /* When marking the block group with
                  * ~EXT4_BG_INODE_UNINIT we don't want to depend
                  * on the value of bg_itable_unused even though
@@ -1196,7 +1226,7 @@ repeat:
 
                 free = 0;
             } else {
-                free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, group_desc);
+                free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gd);
             }
 
             /*
@@ -1206,24 +1236,24 @@ repeat:
              *
              */
             if (dwInode + 1 > free) {
-                ext4_itable_unused_set(sb, group_desc,
+                ext4_itable_unused_set(sb, gd,
                                        (EXT3_INODES_PER_GROUP(sb) - 1 - dwInode));
             }
 
             /* We may have to initialize the block bitmap if it isn't already */
-            if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+            if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
 
                 struct buffer_head *block_bitmap_bh = NULL;
 
                 /* recheck and clear flag under lock if we still need to */
-                block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, group_desc));
+                block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, gd));
                 if (block_bitmap_bh) {
-                    group_desc->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, group_desc);
-                    free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, group_desc);
+                    gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
+                    free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, gd);
                     set_buffer_uptodate(block_bitmap_bh);
                     brelse(block_bitmap_bh);
-                    group_desc->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
-                    ext4_free_blks_set(sb, group_desc, free);
+                    gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
+                    ext4_free_blks_set(sb, gd, free);
                     Ext2SaveGroup(IrpContext, Vcb, Group);
                 }
             }
@@ -1233,7 +1263,7 @@ repeat:
 
         /* update group_desc / super_block */
         if (Type == EXT2_FT_DIR) {
-            ext4_used_dirs_set(sb, group_desc, ext4_used_dirs_count(sb, group_desc) + 1);
+            ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) + 1);
         }
         Ext2SaveGroup(IrpContext, Vcb, Group);
         Ext2UpdateVcbStat(IrpContext, Vcb);
@@ -1244,9 +1274,12 @@ errorout:
 
     ExReleaseResourceLite(&Vcb->MetaLock);
 
-    if (bh) {
-        brelse(bh);
-    }
+    if (bh)
+        fini_bh(&bh);
+
+    if (gb)
+        fini_bh(&gb);
+
 
     return Status;
 }
@@ -1260,7 +1293,8 @@ Ext2FreeInode(
 )
 {
     struct super_block     *sb = &Vcb->sb;
-    PEXT2_GROUP_DESC        group_desc;
+    PEXT2_GROUP_DESC        gd;
+    struct buffer_head     *gb = NULL;
     struct buffer_head     *bh = NULL;
     ext4_fsblk_t            bitmap_blk;
 
@@ -1287,14 +1321,14 @@ Ext2FreeInode(
         goto errorout;
     }
 
-    group_desc = ext4_get_group_desc(sb, Group, NULL);
-    if (!group_desc) {
+    gd = ext4_get_group_desc(sb, Group, &gb);
+    if (!gd) {
         DbgBreak();
         Status = STATUS_INSUFFICIENT_RESOURCES;
         goto errorout;
     }
 
-    bitmap_blk = ext4_inode_bitmap(sb, group_desc);
+    bitmap_blk = ext4_inode_bitmap(sb, gd);
     bh = sb_getblk(sb, bitmap_blk);
     if (!bh) {
         DbgBreak();
@@ -1333,7 +1367,7 @@ Ext2FreeInode(
 
     if (bModified) {
         /* update group free inodes */
-        ext4_free_inodes_set(sb, group_desc,
+        ext4_free_inodes_set(sb, gd,
                              RtlNumberOfClearBits(&InodeBitmap));
 
         /* set inode block dirty and add to vcb dirty range */
@@ -1341,8 +1375,8 @@ Ext2FreeInode(
 
         /* update group_desc and super_block */
         if (Type == EXT2_FT_DIR) {
-            ext4_used_dirs_set(sb, group_desc,
-                               ext4_used_dirs_count(sb, group_desc) - 1);
+            ext4_used_dirs_set(sb, gd,
+                               ext4_used_dirs_count(sb, gd) - 1);
         }
         Ext2SaveGroup(IrpContext, Vcb, Group);
         Ext2UpdateVcbStat(IrpContext, Vcb);
@@ -1353,9 +1387,12 @@ errorout:
 
     ExReleaseResourceLite(&Vcb->MetaLock);
 
-    if (bh) {
-        brelse(bh);
-    }
+    if (bh)
+        fini_bh(&bh);
+
+    if (gb)
+        fini_bh(&gb);
+
     return Status;
 }
 
@@ -1410,8 +1447,10 @@ Ext2AddEntry (
             ext3_inc_count(Inode);
             ext3_mark_inode_dirty(IrpContext, Inode);
 
-            *Dentry = de;
-            de = NULL;
+            if (Dentry) {
+                *Dentry = de;
+                de = NULL;
+            }
         }
 
     } _SEH2_FINALLY {
@@ -1430,6 +1469,69 @@ Ext2AddEntry (
 }
 
 
+NTSTATUS
+Ext2SetFileType (
+    IN PEXT2_IRP_CONTEXT    IrpContext,
+    IN PEXT2_VCB            Vcb,
+    IN PEXT2_FCB            Dcb,
+    IN PEXT2_MCB            Mcb
+    )
+{
+    struct inode *dir = Dcb->Inode;
+    struct buffer_head *bh = NULL;
+    struct ext3_dir_entry_2 *de;
+    struct inode *inode;
+    NTSTATUS Status = STATUS_UNSUCCESSFUL;
+    BOOLEAN  MainResourceAcquired = FALSE;
+
+    if (!EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) {
+        return STATUS_SUCCESS;
+    }
+
+    if (!IsDirectory(Dcb)) {
+        return STATUS_NOT_A_DIRECTORY;
+    }
+
+    ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
+    MainResourceAcquired = TRUE;
+
+    _SEH2_TRY {
+
+        Ext2ReferXcb(&Dcb->ReferenceCount);
+
+        bh = ext3_find_entry(IrpContext, Mcb->de, &de);
+        if (!bh)
+            _SEH2_LEAVE;
+
+        inode = &Mcb->Inode;
+        if (le32_to_cpu(de->inode) != inode->i_ino)
+            _SEH2_LEAVE;
+
+        ext3_set_de_type(inode->i_sb, de, inode->i_mode);
+        mark_buffer_dirty(bh);
+        
+        //if (!inode->i_nlink)
+        //    ext3_orphan_add(handle, inode);
+
+        dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
+        ext3_mark_inode_dirty(IrpContext, dir);
+
+        Status = STATUS_SUCCESS;
+
+    } _SEH2_FINALLY {
+
+        Ext2DerefXcb(&Dcb->ReferenceCount);
+
+        if (MainResourceAcquired)
+            ExReleaseResourceLite(&Dcb->MainResource);
+
+        if (bh)
+            brelse(bh);
+    } _SEH2_END;
+
+    return Status;
+}
+
 NTSTATUS
 Ext2RemoveEntry (
     IN PEXT2_IRP_CONTEXT    IrpContext,
@@ -2259,7 +2361,7 @@ static int ext4_group_used_meta_blocks(struct super_block *sb,
 
     if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
         struct ext4_group_desc *gdp;
-        struct buffer_head *bh;
+        struct buffer_head *bh = NULL;
 
         gdp = ext4_get_group_desc(sb, block_group, &bh);
         if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
@@ -2276,6 +2378,8 @@ static int ext4_group_used_meta_blocks(struct super_block *sb,
             if (!ext4_block_in_group(sb, tmp, block_group))
                 used_blocks -= 1;
         }
+        if (bh)
+            fini_bh(&bh);
     }
     return used_blocks;
 }
@@ -2384,12 +2488,17 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
 struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
                     ext4_group_t block_group, struct buffer_head **bh)
 {
-    unsigned int group_desc;
-    unsigned int offset;
     struct ext4_group_desc *desc = NULL;
+    struct buffer_head  *gb = NULL;
     struct ext3_sb_info *sbi = EXT3_SB(sb);
     PEXT2_VCB vcb = sb->s_priv;
 
+    unsigned int group;
+    unsigned int offset;
+
+    if (bh)
+        *bh = NULL;
+
     if (block_group >= sbi->s_groups_count) {
         ext4_error(sb, "ext4_get_group_desc",
                    "block_group >= groups_count - "
@@ -2400,40 +2509,39 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
     }
     smp_rmb();
 
-    group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
+    group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
     offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
 
-    ExAcquireResourceExclusiveLite(&vcb->MetaLock, TRUE);
-
-    if (!sbi->s_group_desc || !sbi->s_group_desc[group_desc]) {
-        if (!Ext2LoadGroup(vcb)) {
-            ext4_error(sb, "ext4_get_group_desc",
-                       "failed to load group desc: "
-                       "block_group >= groups_count - "
-                       "block_group = %u, groups_count = %u",
-                       block_group, sbi->s_groups_count);
-            goto errorout;
-        }
+    if (!sbi->s_group_desc || !sbi->s_group_desc[group]) {
+        Ext2LoadGroup(vcb);
     }
 
-    if (!sbi->s_group_desc[group_desc]) {
+    if (!sbi->s_group_desc[group]) {
         ext4_error(sb, "ext4_get_group_desc",
                    "Group descriptor not loaded - "
-                   "block_group = %u, group_desc = %u, desc = %u",
-                   block_group, group_desc, offset);
+                   "block_group = %u, group = %u, desc = %u",
+                   block_group, group, offset);
         goto errorout;
     }
 
-    desc = (struct ext4_group_desc *)(
-               (__u8 *)sbi->s_group_desc[group_desc]->b_data +
-               offset * EXT4_DESC_SIZE(sb));
+    gb = sb_getblk(sb, sbi->s_group_desc[group]);
+    if (!gb) {
+        ext4_error(sb, "ext4_get_group_desc",
+                   "failed to load group - "
+                   "block_group = %u, group = %u, desc = %u",
+                   block_group, group, offset);
+        goto errorout;
+    }
+
+    desc = (struct ext4_group_desc *)(gb->b_data +
+                      offset * EXT4_DESC_SIZE(sb));
     if (bh)
-        *bh = sbi->s_group_desc[group_desc];
+        *bh = gb;
+    else
+        fini_bh(&gb);
 
 errorout:
 
-    ExReleaseResourceLite(&vcb->MetaLock);
-
     return desc;
 }
 
@@ -2447,16 +2555,18 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
 {
     ext4_fsblk_t desc_count;
     struct ext4_group_desc *gdp;
+    struct buffer_head *bh = NULL;
     ext4_group_t i;
     ext4_group_t ngroups = EXT3_SB(sb)->s_groups_count;
 
     desc_count = 0;
     smp_rmb();
     for (i = 0; i < ngroups; i++) {
-        gdp = ext4_get_group_desc(sb, i, NULL);
-        if (!gdp)
+        gdp = ext4_get_group_desc(sb, i, &bh);
+        if (!bh)
             continue;
         desc_count += ext4_free_blks_count(sb, gdp);
+        fini_bh(&bh);
     }
 
     return desc_count;
@@ -2466,15 +2576,16 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
 {
     unsigned long desc_count;
     struct ext4_group_desc *gdp;
+    struct buffer_head *bh = NULL;
     ext4_group_t i;
 
     desc_count = 0;
     for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
-        gdp = ext4_get_group_desc(sb, i, NULL);
-        if (!gdp)
+        gdp = ext4_get_group_desc(sb, i, &bh);
+        if (!bh)
             continue;
         desc_count += ext4_free_inodes_count(sb, gdp);
-        cond_resched();
+        fini_bh(&bh);
     }
     return desc_count;
 }
@@ -2482,14 +2593,17 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
 /* Called at mount-time, super-block is locked */
 unsigned long ext4_count_dirs(struct super_block * sb)
 {
+    struct ext4_group_desc *gdp;
+    struct buffer_head *bh = NULL;
     unsigned long count = 0;
     ext4_group_t i;
 
     for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
-        struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
-        if (!gdp)
+        gdp = ext4_get_group_desc(sb, i, &bh);
+        if (!bh)
             continue;
         count += ext4_used_dirs_count(sb, gdp);
+        fini_bh(&bh);
     }
     return count;
 }
@@ -2513,7 +2627,12 @@ int ext4_check_descriptors(struct super_block *sb)
     DEBUG(DL_INF, ("Checking group descriptors"));
 
     for (i = 0; i < sbi->s_groups_count; i++) {
-        struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
+
+        struct buffer_head *bh = NULL;
+        struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, &bh);
+
+        if (!bh)
+            continue;
 
         if (i == sbi->s_groups_count - 1 || flexbg_flag)
             last_block = ext3_blocks_count(sbi->s_es) - 1;
@@ -2526,6 +2645,7 @@ int ext4_check_descriptors(struct super_block *sb)
             printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
                    "Block bitmap for group %u not in group "
                    "(block %llu)!\n", i, block_bitmap);
+            __brelse(bh);
             return 0;
         }
         inode_bitmap = ext4_inode_bitmap(sb, gdp);
@@ -2533,6 +2653,7 @@ int ext4_check_descriptors(struct super_block *sb)
             printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
                    "Inode bitmap for group %u not in group "
                    "(block %llu)!\n", i, inode_bitmap);
+            __brelse(bh);
             return 0;
         }
         inode_table = ext4_inode_table(sb, gdp);
@@ -2541,6 +2662,7 @@ int ext4_check_descriptors(struct super_block *sb)
             printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
                    "Inode table for group %u not in group "
                    "(block %llu)!\n", i, inode_table);
+            __brelse(bh);
             return 0;
         }
 
@@ -2550,12 +2672,15 @@ int ext4_check_descriptors(struct super_block *sb)
                    i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
                                                        gdp)), le16_to_cpu(gdp->bg_checksum));
             if (!IsVcbReadOnly(Vcb)) {
+                __brelse(bh);
                 return 0;
             }
         }
 
         if (!flexbg_flag)
             first_block += EXT4_BLOCKS_PER_GROUP(sb);
+
+        __brelse(bh);
     }
 
     ext3_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
index 186942b..8d5bd4d 100644 (file)
@@ -270,7 +270,7 @@ struct buffer_head *ext3_bread(struct ext2_icb *icb, struct inode *inode,
 
     *err = bh_submit_read(bh);
     if (*err) {
-           brelse(bh);
+           __brelse(bh);
            return NULL;
     }
     return bh;
@@ -402,11 +402,11 @@ int add_dirent_to_buf(struct ext2_icb *icb, struct dentry *dentry,
         while ((char *) de <= top) {
             if (!ext3_check_dir_entry("ext3_add_entry", dir, de,
                                       bh, offset)) {
-                brelse(bh);
+                __brelse(bh);
                 return -EIO;
             }
             if (ext3_match(namelen, name, de)) {
-                brelse(bh);
+                __brelse(bh);
                 return -EEXIST;
             }
             nlen = EXT3_DIR_REC_LEN(de->name_len);
@@ -454,7 +454,7 @@ int add_dirent_to_buf(struct ext2_icb *icb, struct dentry *dentry,
     dir->i_version++;
     ext3_mark_inode_dirty(icb, dir);
     set_buffer_dirty(bh);
-    brelse(bh);
+    __brelse(bh);
     return 0;
 }
 
@@ -971,7 +971,7 @@ struct stats dx_show_entries(struct ext2_icb *icb, struct dx_hash_info *hinfo,
         names += stats.names;
         space += stats.space;
         bcount += stats.bcount;
-        brelse (bh);
+        __brelse (bh);
     }
     if (bcount)
         printk("%snames %u, fullness %u (%u%%)\n", levels?"":"   ",
@@ -1023,7 +1023,7 @@ static struct dx_frame *
         ext3_warning(dir->i_sb, __FUNCTION__,
                      "Unrecognised inode hash code %d",
                      root->info.hash_version);
-        brelse(bh);
+        __brelse(bh);
         *err = ERR_BAD_DX_DIR;
         goto fail;
     }
@@ -2181,7 +2181,7 @@ struct buffer_head * ext3_find_entry (struct ext2_icb *icb,
         return NULL;
 
 #ifdef EXT2_HTREE_INDEX
-    if (is_dx(dir)) {
+    if (icb->MajorFunction != IRP_MJ_CREATE && is_dx(dir)) {
         bh = ext3_dx_find_entry(icb, dentry, res_dir, &err);
         /*
          * On success, or if the error was file not found,
@@ -2264,4 +2264,4 @@ cleanup_and_exit:
     for (; ra_ptr < ra_max; ra_ptr++)
         brelse(bh_use[ra_ptr]);
     return ret;
-}
\ No newline at end of file
+}
index 2c5401c..4270c15 100644 (file)
@@ -3,7 +3,7 @@
  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
  * FILE:             recover.c
  * PROGRAMMER:       Matt Wu <mattwu@163.com>
- * HOMEPAGE:         http://ext2.yeah.net
+ * HOMEPAGE:         http://www.ext2fsd.com
  * UPDATE HISTORY:
  */
 
index 9becba0..a874bbd 100644 (file)
@@ -52,3 +52,17 @@ void extents_brelse(struct buffer_head *bh)
 {
     brelse(bh);
 }
+
+/*
+ * extents_bforget: Release the corresponding buffer header.
+ * NOTE: The page owned by @bh will be marked invalidated.
+ *
+ * @bh: The corresponding buffer header that is going to be freed.
+ *
+ * The pages underlying the buffer header will be unlocked.
+ */
+void extents_bforget(struct buffer_head *bh)
+{
+    clear_buffer_uptodate(bh);
+    bforget(bh);
+}
index 80ce39e..a135b4a 100644 (file)
@@ -878,7 +878,7 @@ static int ext4_ext_split(void *icb, handle_t *handle, struct inode *inode,
        neh = ext_block_hdr(bh);
        neh->eh_entries = 0;
        neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
-       neh->eh_magic = EXT4_EXT_MAGIC;
+       neh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
        neh->eh_depth = 0;
 
        /* move remainder of path[depth] to the new leaf */
@@ -948,7 +948,7 @@ static int ext4_ext_split(void *icb, handle_t *handle, struct inode *inode,
 
                neh = ext_block_hdr(bh);
                neh->eh_entries = cpu_to_le16(1);
-               neh->eh_magic = EXT4_EXT_MAGIC;
+               neh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
                neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
                neh->eh_depth = cpu_to_le16(depth - i);
                fidx = EXT_FIRST_INDEX(neh);
@@ -1064,10 +1064,10 @@ static int ext4_ext_grow_indepth(void *icb, handle_t *handle, struct inode *inod
        /* old root could have indexes or leaves
         * so calculate e_max right way */
        if (ext_depth(inode))
-               neh->eh_max = (ext4_ext_space_block_idx(inode, 0));
+               neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
        else
-               neh->eh_max = (ext4_ext_space_block(inode, 0));
-       neh->eh_magic = EXT4_EXT_MAGIC;
+               neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
+       neh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
        ext4_extent_block_csum_set(inode, neh);
        set_buffer_uptodate(bh);
 
@@ -1077,11 +1077,11 @@ static int ext4_ext_grow_indepth(void *icb, handle_t *handle, struct inode *inod
 
        /* Update top-level index: num,max,pointer */
        neh = ext_inode_hdr(inode);
-       neh->eh_entries = (1);
+       neh->eh_entries = cpu_to_le16(1);
        ext4_idx_store_pblock(EXT_FIRST_INDEX(neh), newblock);
        if (neh->eh_depth == 0) {
                /* Root extent block becomes index block */
-               neh->eh_max = (ext4_ext_space_root_idx(inode, 0));
+               neh->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0));
                EXT_FIRST_INDEX(neh)->ei_block =
                        EXT_FIRST_EXTENT(neh)->ee_block;
        }
@@ -2310,7 +2310,7 @@ int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode)
        eh = ext_inode_hdr(inode);
        eh->eh_depth = 0;
        eh->eh_entries = 0;
-       eh->eh_magic = EXT4_EXT_MAGIC;
+       eh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
        eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
        ext4_mark_inode_dirty(icb, handle, inode);
        return 0;
@@ -2502,6 +2502,17 @@ out2:
        return err ? err : allocated;
 }
 
+int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start)
+{
+    int ret = ext4_ext_remove_space(icb, inode, start);
+
+       /* Save modifications on i_blocks field of the inode. */
+       if (!ret)
+               ret = ext4_mark_inode_dirty(icb, NULL, inode);
+
+       return ret;
+}
+
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
index d823ea1..c132911 100644 (file)
@@ -33,7 +33,7 @@ Ext2MapExtent(
 )
 {
     EXT4_EXTENT_HEADER *eh;
-    struct buffer_head bh_got;
+    struct buffer_head bh_got = {0};
     int    flags, rc;
        ULONG max_blocks = 0;
 
@@ -67,6 +67,16 @@ Ext2MapExtent(
         flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
                max_blocks = EXT_UNWRITTEN_MAX_LEN;
     }
+    
+    if (Alloc) {
+        if (Number && !*Number) {
+            if (max_blocks > *Number) {
+                max_blocks = *Number;
+            }
+        } else {
+            max_blocks = 1;
+        }
+    }
 
     if ((rc = ext4_ext_get_blocks(
                             IrpContext,
@@ -209,7 +219,7 @@ Ext2TruncateExtent(
     /* calculate blocks to be freed */
     Extra = End - Wanted;
 
-       err = ext4_ext_remove_space(IrpContext, &Mcb->Inode, Wanted);
+    err = ext4_ext_truncate(IrpContext, &Mcb->Inode, Wanted);
     if (err == 0) {
         if (!Ext2RemoveBlockExtent(Vcb, Mcb, Wanted, Extra)) {
             ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
@@ -224,9 +234,10 @@ Ext2TruncateExtent(
         Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS);
     }
 
-    /* save inode */
     if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart))
         Mcb->Inode.i_size = (loff_t)(Size->QuadPart);
+
+    /* Save modifications on i_blocks field and i_size field of the inode. */
     Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
 
     return Status;
index 7885b08..56e7ae6 100644 (file)
@@ -213,18 +213,24 @@ Ext2FastIoWrite (
             _SEH2_LEAVE;
         }
 
-        ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
-        Locked = TRUE;
+        if (ExAcquireResourceExclusiveLite(&Fcb->MainResource, Wait))
+            Locked = TRUE;
+        else
+            _SEH2_LEAVE;
 
         if (IsWritingToEof(*FileOffset) ||
-            Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart ||
             Fcb->Header.FileSize.QuadPart < FileOffset->QuadPart + Length ) {
             Status = FALSE;
-        } else {
-            ExReleaseResourceLite(&Fcb->MainResource);
-            Locked = FALSE;
-            Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait,
-                                    LockKey, Buffer, IoStatus, DeviceObject);
+            _SEH2_LEAVE;
+        }
+
+        Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait,
+                                LockKey, Buffer, IoStatus, DeviceObject);
+        if (Status) {
+            if (IoStatus)
+                Length = (ULONG)IoStatus->Information;
+            if (Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length)
+                Fcb->Header.ValidDataLength.QuadPart = FileOffset->QuadPart + Length;
         }
 
     } _SEH2_FINALLY {
@@ -251,6 +257,8 @@ Ext2FastIoQueryBasicInfo (
     IN PDEVICE_OBJECT           DeviceObject)
 {
     PEXT2_FCB   Fcb = NULL;
+    PEXT2_CCB   Ccb = NULL;
+    PEXT2_MCB   Mcb = NULL;
     BOOLEAN     Status = FALSE;
     BOOLEAN     FcbMainResourceAcquired = FALSE;
 
@@ -270,7 +278,8 @@ Ext2FastIoQueryBasicInfo (
                 IoStatus->Status = STATUS_INVALID_PARAMETER;
                 _SEH2_LEAVE;
             }
-
+            Ccb = (PEXT2_CCB) FileObject->FsContext2;
+            Mcb = Fcb->Mcb;
             ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                    (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
 #if EXT2_DEBUG
@@ -302,17 +311,11 @@ Ext2FastIoQueryBasicInfo (
             } FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
             */
 
-            if (IsRoot(Fcb)) {
-                Buffer->CreationTime = Buffer->LastAccessTime =
-                                           Buffer->LastWriteTime = Buffer->ChangeTime = Ext2NtTime(0);
-            } else {
-                Buffer->CreationTime = Fcb->Mcb->CreationTime;
-                Buffer->LastAccessTime = Fcb->Mcb->LastAccessTime;
-                Buffer->LastWriteTime = Fcb->Mcb->LastWriteTime;
-                Buffer->ChangeTime = Fcb->Mcb->ChangeTime;
-            }
-
-            Buffer->FileAttributes = Fcb->Mcb->FileAttr;
+            Buffer->CreationTime = Mcb->CreationTime;
+            Buffer->LastAccessTime = Mcb->LastAccessTime;
+            Buffer->LastWriteTime = Mcb->LastWriteTime;
+            Buffer->ChangeTime = Mcb->ChangeTime;
+            Buffer->FileAttributes = Mcb->FileAttr;
             if (Buffer->FileAttributes == 0) {
                 Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
             }
@@ -368,8 +371,8 @@ Ext2FastIoQueryStandardInfo (
 {
 
     BOOLEAN     Status = FALSE;
-    PEXT2_VCB   Vcb;
-    PEXT2_FCB   Fcb;
+    PEXT2_VCB   Vcb = NULL;
+    PEXT2_FCB   Fcb = NULL;
     BOOLEAN     FcbMainResourceAcquired = FALSE;
 
     _SEH2_TRY {
@@ -892,10 +895,11 @@ Ext2FastIoQueryNetworkOpenInfo (
     IN PDEVICE_OBJECT       DeviceObject
 )
 {
-    BOOLEAN     bResult = FALSE;
-
     PEXT2_FCB   Fcb = NULL;
+    PEXT2_CCB   Ccb = NULL;
+    PEXT2_MCB   Mcb = NULL;
 
+    BOOLEAN     bResult = FALSE;
     BOOLEAN FcbResourceAcquired = FALSE;
 
     _SEH2_TRY {
@@ -916,6 +920,8 @@ Ext2FastIoQueryNetworkOpenInfo (
 
         ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+        Ccb = (PEXT2_CCB) FileObject->FsContext2;
+        Mcb = Fcb->Mcb;
 
 #if EXT2_DEBUG
         DEBUG(DL_INF, (
@@ -925,7 +931,7 @@ Ext2FastIoQueryNetworkOpenInfo (
               ));
 #endif
 
-        if (FileObject->FsContext2) {
+        if (!Ccb) {
             _SEH2_LEAVE;
         }
 
@@ -949,22 +955,15 @@ Ext2FastIoQueryNetworkOpenInfo (
             PFNOI->EndOfFile      = Fcb->Header.FileSize;
         }
 
-        PFNOI->FileAttributes = Fcb->Mcb->FileAttr;
+        PFNOI->FileAttributes = Mcb->FileAttr;
         if (PFNOI->FileAttributes == 0) {
             PFNOI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
         }
 
-        if (IsRoot(Fcb)) {
-            PFNOI->CreationTime =
-                PFNOI->LastAccessTime =
-                    PFNOI->LastWriteTime =
-                        PFNOI->ChangeTime = Ext2NtTime(0);
-        } else {
-            PFNOI->CreationTime   = Fcb->Mcb->CreationTime;
-            PFNOI->LastAccessTime = Fcb->Mcb->LastAccessTime;
-            PFNOI->LastWriteTime  = Fcb->Mcb->LastWriteTime;
-            PFNOI->ChangeTime     = Fcb->Mcb->ChangeTime;
-        }
+        PFNOI->CreationTime   = Mcb->CreationTime;
+        PFNOI->LastAccessTime = Mcb->LastAccessTime;
+        PFNOI->LastWriteTime  = Mcb->LastWriteTime;
+        PFNOI->ChangeTime     = Mcb->ChangeTime;
 
         bResult = TRUE;
 
index 3588b47..f00035d 100644 (file)
@@ -25,6 +25,7 @@ extern PEXT2_GLOBAL Ext2Global;
 #pragma alloc_text(PAGE, Ext2TruncateFile)
 #pragma alloc_text(PAGE, Ext2SetDispositionInfo)
 #pragma alloc_text(PAGE, Ext2SetRenameInfo)
+#pragma alloc_text(PAGE, Ext2SetLinkInfo)
 #pragma alloc_text(PAGE, Ext2DeleteFile)
 #endif
 
@@ -34,11 +35,11 @@ Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
     PDEVICE_OBJECT          DeviceObject;
     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
     PFILE_OBJECT            FileObject;
-    PEXT2_VCB               Vcb;
-    PEXT2_FCB               Fcb;
-    PEXT2_MCB               Mcb;
-    PEXT2_CCB               Ccb;
-    PIRP                    Irp;
+    PEXT2_VCB               Vcb = NULL;
+    PEXT2_FCB               Fcb = NULL;
+    PEXT2_MCB               Mcb = NULL;
+    PEXT2_CCB               Ccb = NULL;
+    PIRP                    Irp = NULL;
     PIO_STACK_LOCATION      IoStackLocation;
     FILE_INFORMATION_CLASS  FileInformationClass;
     ULONG                   Length;
@@ -489,13 +490,13 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     PDEVICE_OBJECT          DeviceObject;
     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
-    PEXT2_VCB               Vcb;
-    PFILE_OBJECT            FileObject;
-    PEXT2_FCB               Fcb;
-    PEXT2_CCB               Ccb;
-    PEXT2_MCB               Mcb;
-    PIRP                    Irp;
-    PIO_STACK_LOCATION      IoStackLocation;
+    PEXT2_VCB               Vcb = NULL;
+    PFILE_OBJECT            FileObject = NULL;
+    PEXT2_FCB               Fcb = NULL;
+    PEXT2_CCB               Ccb = NULL;
+    PEXT2_MCB               Mcb = NULL;
+    PIRP                    Irp = NULL;
+    PIO_STACK_LOCATION      IoStackLocation = NULL;
     FILE_INFORMATION_CLASS  FileInformationClass;
 
     ULONG                   NotifyFilter = 0;
@@ -541,8 +542,9 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
             _SEH2_LEAVE;
         }
 
-        /* we need grab Vcb in case it's a rename operation */
-        if (FileInformationClass == FileRenameInformation) {
+        /* we need grab Vcb in case it's rename or sethardlink */
+        if (FileInformationClass == FileRenameInformation ||
+            FileInformationClass == FileLinkInformation) {
             if (!ExAcquireResourceExclusiveLite(
                         &Vcb->MainResource,
                         IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
@@ -616,10 +618,11 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
             Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
         }
 
-        /* for renaming, we must not get any Fcb locks here, function
-           Ext2SetRenameInfo will get Dcb resource exclusively.  */
+        /* for renaming or set link, we must not grab any Fcb locks,
+           and later we will get Dcb or Fcb resources exclusively.  */
         if (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) &&
-                FileInformationClass != FileRenameInformation) {
+            FileInformationClass != FileRenameInformation &&
+            FileInformationClass != FileLinkInformation) {
 
             if (!ExAcquireResourceExclusiveLite(
                         &Fcb->MainResource,
@@ -975,6 +978,14 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
 
         break;
 
+
+        case FileLinkInformation:
+        {
+            Status = Ext2SetLinkInfo(IrpContext, Vcb, Fcb, Ccb);
+        }
+
+        break;
+
         //
         // This is the only set file information request supported on read
         // only file systems
@@ -1006,11 +1017,6 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
 
         break;
 
-        case FileLinkInformation:
-
-            Status = STATUS_INVALID_DEVICE_REQUEST;
-            break;
-
         default:
             DEBUG(DL_WRN, ( "Ext2SetInformation: invalid class: %d\n",
                             FileInformationClass));
@@ -1656,6 +1662,262 @@ errorout:
     return Status;
 }
 
+NTSTATUS
+Ext2SetLinkInfo(
+    PEXT2_IRP_CONTEXT IrpContext,
+    PEXT2_VCB         Vcb,
+    PEXT2_FCB         Fcb,
+    PEXT2_CCB         Ccb
+)
+{
+    PEXT2_MCB               Mcb = Fcb->Mcb;
+
+    PEXT2_FCB               TargetDcb = NULL;   /* Dcb of target directory */
+    PEXT2_MCB               TargetMcb = NULL;
+    PEXT2_FCB               ParentDcb = NULL;   /* Dcb of it's current parent */
+    PEXT2_MCB               ParentMcb = NULL;
+
+    PEXT2_FCB               ExistingFcb = NULL; /* Target file Fcb if it exists*/
+    PEXT2_MCB               ExistingMcb = NULL;
+    PEXT2_MCB               LinkMcb = NULL;     /* Mcb for new hardlink */
+
+    UNICODE_STRING          FileName;
+
+    NTSTATUS                Status;
+
+    PIRP                    Irp;
+    PIO_STACK_LOCATION      IrpSp;
+
+    PFILE_OBJECT            FileObject;
+    PFILE_OBJECT            TargetObject;
+
+    BOOLEAN                 ReplaceIfExists;
+    BOOLEAN                 bTargetRemoved = FALSE;
+    BOOLEAN                 bNewTargetDcb = FALSE;
+    BOOLEAN                 bNewParentDcb = FALSE;
+
+    PFILE_LINK_INFORMATION  FLI;
+
+    if (Ccb->SymLink) {
+        Mcb = Ccb->SymLink;
+    }
+
+    if (IsMcbDirectory(Mcb)) {
+        Status = STATUS_INVALID_PARAMETER;
+        goto errorout;
+    }
+
+    Irp = IrpContext->Irp;
+    IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    FileObject = IrpSp->FileObject;
+    TargetObject = IrpSp->Parameters.SetFile.FileObject;
+    ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
+
+    FLI = (PFILE_LINK_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+    if (TargetObject == NULL) {
+
+        UNICODE_STRING  NewName;
+
+        NewName.Buffer = FLI->FileName;
+        NewName.MaximumLength = NewName.Length = (USHORT)FLI->FileNameLength;
+
+        while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') {
+            NewName.Buffer[NewName.Length/2 - 1] = 0;
+            NewName.Length -= 2;
+        }
+
+        while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') {
+            NewName.Length -= 2;
+        }
+
+        NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length);
+        NewName.Length = (USHORT)(FLI->FileNameLength - NewName.Length);
+
+        FileName = NewName;
+
+        TargetMcb = Mcb->Parent;
+        if (IsMcbSymLink(TargetMcb)) {
+            TargetMcb = TargetMcb->Target;
+            ASSERT(!IsMcbSymLink(TargetMcb));
+        }
+
+        if (TargetMcb == NULL || FileName.Length >= EXT2_NAME_LEN*2) {
+            Status = STATUS_OBJECT_NAME_INVALID;
+            goto errorout;
+        }
+
+    } else {
+
+        TargetDcb = (PEXT2_FCB)(TargetObject->FsContext);
+        if (!TargetDcb || TargetDcb->Vcb != Vcb) {
+            DbgBreak();
+            Status = STATUS_INVALID_PARAMETER;
+            goto errorout;
+        }
+
+        TargetMcb = TargetDcb->Mcb;
+        FileName = TargetObject->FileName;
+    }
+
+    if (FsRtlDoesNameContainWildCards(&FileName)) {
+        Status = STATUS_OBJECT_NAME_INVALID;
+        goto errorout;
+    }
+
+    if (TargetMcb->Inode.i_ino == Mcb->Parent->Inode.i_ino) {
+        if (FsRtlAreNamesEqual( &FileName,
+                                &(Mcb->ShortName),
+                                FALSE,
+                                NULL )) {
+            Status = STATUS_SUCCESS;
+            goto errorout;
+        }
+    }
+
+    TargetDcb = TargetMcb->Fcb;
+    if (TargetDcb == NULL) {
+        TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb);
+        if (TargetDcb) {
+            Ext2ReferXcb(&TargetDcb->ReferenceCount);
+            bNewTargetDcb = TRUE;
+        }
+    }
+
+    if (TargetDcb) {
+        SetLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
+    }
+
+    ParentMcb = Mcb->Parent;
+    ParentDcb = ParentMcb->Fcb;
+
+    if ((TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino)) {
+
+        if (ParentDcb == NULL) {
+            ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+            if (ParentDcb) {
+                Ext2ReferXcb(&ParentDcb->ReferenceCount);
+                bNewParentDcb = TRUE;
+            }
+        }
+        if (ParentDcb) {
+            SetLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
+        }
+    }
+
+    if (!TargetDcb || !ParentDcb) {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto errorout;
+    }
+
+    DEBUG(DL_RES, ("Ext2SetLinkInfo: %wZ\\%wZ -> %wZ\n",
+                   &TargetMcb->FullName, &FileName, &Mcb->FullName));
+
+    Status = Ext2LookupFile(IrpContext, Vcb, &FileName,
+                            TargetMcb, &ExistingMcb, 0);
+    if (NT_SUCCESS(Status) && ExistingMcb != Mcb) {
+
+        if (!ReplaceIfExists) {
+
+            Status = STATUS_OBJECT_NAME_COLLISION;
+            DEBUG(DL_RES, ("Ext2SetRenameInfo: Target file %wZ exists\n",
+                           &ExistingMcb->FullName));
+            goto errorout;
+
+        } else {
+
+            if ( (ExistingFcb = ExistingMcb->Fcb) && !IsMcbSymLink(ExistingMcb) ) {
+                Status = Ext2IsFileRemovable(IrpContext, Vcb, ExistingFcb, Ccb);
+                if (!NT_SUCCESS(Status)) {
+                    DEBUG(DL_REN, ("Ext2SetRenameInfo: Target file %wZ cannot be removed.\n",
+                                   &ExistingMcb->FullName));
+                    goto errorout;
+                }
+            }
+
+            Status = Ext2DeleteFile(IrpContext, Vcb, ExistingFcb, ExistingMcb);
+            if (!NT_SUCCESS(Status)) {
+                DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to delete %wZ with status: %xh.\n",
+                               &FileName, Status));
+
+                goto errorout;
+            }
+            bTargetRemoved = TRUE;
+        }
+    }
+
+    /* add new entry for new target name */
+    Status = Ext2AddEntry(IrpContext, Vcb, TargetDcb, &Mcb->Inode, &FileName, NULL);
+    if (!NT_SUCCESS(Status)) {
+        DEBUG(DL_REN, ("Ext2SetLinkInfo: Failed to add entry for %wZ with status: %xh.\n",
+                       &FileName, Status));
+        goto errorout;
+    }
+
+    if (bTargetRemoved) {
+        Ext2NotifyReportChange(
+            IrpContext,
+            Vcb,
+            ExistingMcb,
+            (IsMcbDirectory(ExistingMcb) ?
+             FILE_NOTIFY_CHANGE_DIR_NAME :
+             FILE_NOTIFY_CHANGE_FILE_NAME ),
+            FILE_ACTION_REMOVED);
+    }
+
+    if (NT_SUCCESS(Status)) {
+
+        Ext2LookupFile(IrpContext, Vcb, &FileName, TargetMcb, &LinkMcb, 0);
+        if (!LinkMcb)
+            goto errorout;
+
+        Ext2NotifyReportChange(
+            IrpContext,
+            Vcb,
+            LinkMcb,
+            FILE_NOTIFY_CHANGE_FILE_NAME,
+            FILE_ACTION_ADDED);
+    }
+
+errorout:
+
+    if (TargetDcb) {
+        if (ParentDcb && ParentDcb->Inode->i_ino != TargetDcb->Inode->i_ino) {
+            ClearLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
+        }
+        ClearLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
+    }
+
+    if (bNewTargetDcb) {
+        ASSERT(TargetDcb != NULL);
+        if (Ext2DerefXcb(&TargetDcb->ReferenceCount) == 0) {
+            Ext2FreeFcb(TargetDcb);
+            TargetDcb = NULL;
+        } else {
+            DEBUG(DL_RES, ( "Ext2SetLinkInfo: TargetDcb is resued by other threads.\n"));
+        }
+    }
+
+    if (bNewParentDcb) {
+        ASSERT(ParentDcb != NULL);
+        if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
+            Ext2FreeFcb(ParentDcb);
+            ParentDcb = NULL;
+        } else {
+            DEBUG(DL_RES, ( "Ext2SeLinkInfo: ParentDcb is resued by other threads.\n"));
+        }
+    }
+
+    if (ExistingMcb)
+        Ext2DerefMcb(ExistingMcb);
+
+    if (LinkMcb)
+        Ext2DerefMcb(LinkMcb);
+
+    return Status;
+}
+
 ULONG
 Ext2InodeType(PEXT2_MCB Mcb)
 {
@@ -1705,7 +1967,6 @@ Ext2DeleteFile(
         }
     }
 
-
     _SEH2_TRY {
 
         Ext2ReferMcb(Mcb);
index 136cf26..dba95f5 100644 (file)
@@ -96,39 +96,48 @@ Ext2FlushFile (
     IN PEXT2_CCB            Ccb
 )
 {
-    IO_STATUS_BLOCK    IoStatus;
+    IO_STATUS_BLOCK     IoStatus;
 
     ASSERT(Fcb != NULL);
     ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
            (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
 
-    /* update timestamp and achieve attribute */
-    if (Ccb != NULL) {
+    _SEH2_TRY {
+
+        /* update timestamp and achieve attribute */
+        if (Ccb != NULL) {
 
-        if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
+            if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
 
-            LARGE_INTEGER   SysTime;
-            KeQuerySystemTime(&SysTime);
+                LARGE_INTEGER   SysTime;
+                KeQuerySystemTime(&SysTime);
 
-            Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
-            Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime);
-            Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode);
+                Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
+                Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime);
+                Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode);
+            }
         }
-    }
 
-    if (IsDirectory(Fcb)) {
-        return STATUS_SUCCESS;
-    }
+        if (IsDirectory(Fcb)) {
+            IoStatus.Status = STATUS_SUCCESS;
+            _SEH2_LEAVE;
+        }
+
+        DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n",
+                        Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer));
 
-    DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n",
-                    Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer));
+        CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus);
+        ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+
+    } _SEH2_FINALLY {
 
-    CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus);
-    ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+        /* do cleanup here */
+    } _SEH2_END;
 
     return IoStatus.Status;
 }
 
+
 NTSTATUS
 Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext)
 {
@@ -189,9 +198,7 @@ Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext)
         }
 
         MainResourceAcquired =
-            ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource,
-                                           IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
-
+            ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource, TRUE);
         ASSERT(MainResourceAcquired);
         DEBUG(DL_INF, ("Ext2Flush-pre:  total mcb records=%u\n",
                        FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
@@ -265,4 +272,4 @@ Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext)
     } _SEH2_END;
 
     return Status;
-}
\ No newline at end of file
+}
index 124b739..5ff4264 100644 (file)
@@ -137,7 +137,7 @@ Ext2LockVolume (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     PIO_STACK_LOCATION IrpSp;
     PDEVICE_OBJECT  DeviceObject;
-    PEXT2_VCB       Vcb;
+    PEXT2_VCB       Vcb = NULL;
     NTSTATUS        Status;
     BOOLEAN VcbResourceAcquired = FALSE;
 
@@ -242,10 +242,10 @@ Ext2UnlockVolume (
     IN PEXT2_IRP_CONTEXT IrpContext
 )
 {
-    PIO_STACK_LOCATION IrpSp;
-    PDEVICE_OBJECT  DeviceObject;
+    PIO_STACK_LOCATION IrpSp = NULL;
+    PDEVICE_OBJECT  DeviceObject = NULL;
+    PEXT2_VCB       Vcb = NULL;
     NTSTATUS        Status;
-    PEXT2_VCB       Vcb;
     BOOLEAN         VcbResourceAcquired = FALSE;
 
     _SEH2_TRY {
@@ -1289,6 +1289,595 @@ Ext2GetRetrievalPointerBase (
     return Status;
 }
 
+NTSTATUS
+Ext2InspectReparseData(
+    IN PREPARSE_DATA_BUFFER RDB,
+    IN ULONG InputBufferLength
+)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    if (!RDB) {
+        Status = STATUS_INVALID_PARAMETER;
+        goto out;
+    }
+
+    if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
+        Status = STATUS_BUFFER_OVERFLOW;
+        goto out;
+    }
+
+    if (InputBufferLength < RDB->ReparseDataLength) {
+        Status = STATUS_BUFFER_OVERFLOW;
+        goto out;
+    }
+
+    if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
+        Status = STATUS_NOT_IMPLEMENTED;
+        goto out;
+    }
+
+    if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
+          + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset
+          + RDB->SymbolicLinkReparseBuffer.SubstituteNameLength
+        > (PUCHAR)RDB + InputBufferLength ) {
+        Status = STATUS_BUFFER_OVERFLOW;
+        goto out;
+    }
+
+    if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
+          + RDB->SymbolicLinkReparseBuffer.PrintNameOffset
+          + RDB->SymbolicLinkReparseBuffer.PrintNameLength
+        > (PUCHAR)RDB + InputBufferLength) {
+        Status = STATUS_BUFFER_OVERFLOW;
+        goto out;
+    }
+
+    if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) {
+        Status = STATUS_NOT_IMPLEMENTED;
+        goto out;
+    }
+
+out:
+    return Status;
+}
+
+VOID
+Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength)
+{
+    ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) ==
+           REPARSE_DATA_BUFFER_HEADER_SIZE);
+    RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK;
+    RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+                             FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+                             PathBufferLength * sizeof(WCHAR);
+    RDB->Reserved = 0;
+    RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength;
+    RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength;
+    RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+    RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength;
+    RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
+    RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2);
+}
+
+NTSTATUS
+Ext2ReadSymlink (
+    IN PEXT2_IRP_CONTEXT    IrpContext,
+    IN PEXT2_VCB            Vcb,
+    IN PEXT2_MCB            Mcb,
+    IN PVOID                Buffer,
+    IN ULONG                Size,
+    OUT PULONG              BytesRead
+    )
+{
+    return Ext2ReadInode (  IrpContext,
+                            Vcb,
+                            Mcb,
+                            0,
+                            Buffer,
+                            Size,
+                            FALSE,
+                            BytesRead);
+}
+
+
+
+NTSTATUS
+Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+    PIRP                        Irp = NULL;
+    PIO_STACK_LOCATION          IrpSp;
+    PEXTENDED_IO_STACK_LOCATION EIrpSp;
+
+    PDEVICE_OBJECT      DeviceObject;
+
+    PEXT2_VCB           Vcb = NULL;
+    PEXT2_CCB           Ccb = NULL;
+    PEXT2_MCB           Mcb = NULL;
+
+    NTSTATUS            Status = STATUS_UNSUCCESSFUL;
+    BOOLEAN             MainResourceAcquired = FALSE;
+
+    PVOID               OutputBuffer;
+    ULONG               OutputBufferLength;
+    ULONG               BytesRead = 0;
+
+    PREPARSE_DATA_BUFFER RDB;
+
+    UNICODE_STRING  UniName;
+    OEM_STRING      OemName;
+    
+    PCHAR           OemNameBuffer = NULL;
+    int             OemNameLength = 0, i;
+
+    Ccb = IrpContext->Ccb;
+    ASSERT(Ccb != NULL);
+    ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+           (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+    DeviceObject = IrpContext->DeviceObject;
+    Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+    Mcb = IrpContext->Fcb->Mcb;
+    Irp = IrpContext->Irp;
+    IrpSp = IoGetCurrentIrpStackLocation(Irp);
+    
+    _SEH2_TRY {
+
+        if (!Mcb || !IsInodeSymLink(&Mcb->Inode)) {
+            Status = STATUS_NOT_A_REPARSE_POINT;
+            _SEH2_LEAVE;
+        }
+        
+        OutputBuffer  = (PVOID)Irp->AssociatedIrp.SystemBuffer;
+        OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+
+        RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
+        if (!RDB) {
+            Status = STATUS_INVALID_PARAMETER;
+            _SEH2_LEAVE;
+        }
+        if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
+            Status = STATUS_BUFFER_OVERFLOW;
+            _SEH2_LEAVE;
+        }
+
+        OemNameLength = (ULONG)Mcb->Inode.i_size;
+        if (OemNameLength > USHRT_MAX) {
+            Status = STATUS_INVALID_PARAMETER;
+            _SEH2_LEAVE;
+        }
+        OemName.Length = (USHORT)OemNameLength;
+        OemName.MaximumLength = OemNameLength + 1;
+        OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
+                                          OemName.MaximumLength,
+                                          'NL2E');
+        if (!OemNameBuffer) {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            _SEH2_LEAVE;
+        }
+
+        Status = Ext2ReadSymlink(IrpContext,
+                                 Vcb,
+                                 Mcb,
+                                 OemNameBuffer,
+                                 OemNameLength,
+                                 &BytesRead
+                                );
+        OemName.Buffer[OemName.Length] = '\0';
+        for (i = 0;i < OemName.Length;i++) {
+            if (OemName.Buffer[i] == '/') {
+                OemName.Buffer[i] = '\\';
+            }
+        }
+
+        if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
+            UniName.Length = USHRT_MAX;
+        } else {
+            UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
+        }
+        UniName.MaximumLength = UniName.Length;
+        UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
+        Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
+        if (UniName.MaximumLength < 2*UniName.Length) {
+            Status = STATUS_BUFFER_TOO_SMALL;
+            _SEH2_LEAVE;
+        }
+
+        Ext2InitializeReparseData(RDB, UniName.Length);
+        UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
+        /*
+            (PWCHAR)((PUCHAR)&
+             + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+         */
+        Ext2OEMToUnicode(Vcb, &UniName, &OemName);
+        RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
+                               RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
+                       UniName.Buffer, UniName.Length);
+        
+        Status = STATUS_SUCCESS;
+
+    } _SEH2_FINALLY {
+        
+        if (OemNameBuffer) {
+            Ext2FreePool(OemNameBuffer, 'NL2E');
+        }
+
+        if (!_SEH2_AbnormalTermination()) {
+            if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+                Status = Ext2QueueRequest(IrpContext);
+            } else {
+                Ext2CompleteIrpContext(IrpContext, Status);
+            }
+        }
+    } _SEH2_END;
+    
+    return Status;
+}
+
+
+NTSTATUS
+Ext2WriteSymlink (
+    IN PEXT2_IRP_CONTEXT    IrpContext,
+    IN PEXT2_VCB            Vcb,
+    IN PEXT2_MCB            Mcb,
+    IN PVOID                Buffer,
+    IN ULONG                Size,
+    OUT PULONG              BytesWritten
+)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PUCHAR   Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
+
+    if (Size >= EXT2_LINKLEN_IN_INODE) {
+
+        /* initialize inode i_block[] */
+        if (0 == Mcb->Inode.i_blocks) {
+            memset(Data, 0, EXT2_LINKLEN_IN_INODE);
+            ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+            Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+        }
+
+        Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
+                                0, Buffer, Size,
+                                FALSE, BytesWritten);
+        if (!NT_SUCCESS(Status)) {
+            goto out;
+        }
+
+    } else {
+
+        /* free inode blocks before writing in line */
+        if (Mcb->Inode.i_blocks) {
+            LARGE_INTEGER Zero = {0, 0};
+            Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
+        }
+
+        ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+        memset(Data, 0, EXT2_LINKLEN_IN_INODE);
+        RtlCopyMemory(Data, Buffer, Size);
+    }
+
+    Mcb->Inode.i_size = Size;
+    Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+
+    if (BytesWritten) {
+        *BytesWritten = Size;
+    }
+
+out:
+    return Status;
+}
+
+
+NTSTATUS
+Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+    PIRP                Irp = NULL;
+    PIO_STACK_LOCATION  IrpSp;
+
+    PDEVICE_OBJECT      DeviceObject;
+
+    PEXT2_VCB           Vcb = NULL;
+    PEXT2_FCB           Fcb = NULL;
+    PEXT2_CCB           Ccb = NULL;
+    PEXT2_MCB           Mcb = NULL;
+
+    NTSTATUS            Status = STATUS_UNSUCCESSFUL;
+    BOOLEAN             bNewParentDcb = FALSE;
+    BOOLEAN             MainResourceAcquired = FALSE;
+    
+    PVOID               InputBuffer;
+    ULONG               InputBufferLength;
+    ULONG               BytesWritten = 0;
+
+    PEXT2_FCB           ParentDcb = NULL;   /* Dcb of it's current parent */
+    PEXT2_MCB           ParentMcb = NULL;
+
+    PREPARSE_DATA_BUFFER RDB;
+
+    UNICODE_STRING      UniName;
+    OEM_STRING          OemName;
+    
+    PCHAR               OemNameBuffer = NULL;
+    int                 OemNameLength = 0, i;
+
+
+    _SEH2_TRY {
+
+        Ccb = IrpContext->Ccb;
+        ASSERT(Ccb != NULL);
+        ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+               (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+        DeviceObject = IrpContext->DeviceObject;
+        Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+        Fcb = IrpContext->Fcb;
+        Mcb = Fcb->Mcb;
+        Irp = IrpContext->Irp;
+        IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+        ParentMcb = Mcb->Parent;
+        ParentDcb = ParentMcb->Fcb;
+        if (ParentDcb == NULL) {
+            ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+            if (ParentDcb) {
+                Ext2ReferXcb(&ParentDcb->ReferenceCount);
+                bNewParentDcb = TRUE;
+            }
+        }
+
+        if (!Mcb)
+            _SEH2_LEAVE;
+
+        if (!ExAcquireResourceSharedLite(
+                    &Fcb->MainResource,
+                    IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+            Status = STATUS_PENDING;
+            _SEH2_LEAVE;
+        }
+        MainResourceAcquired = TRUE;
+        
+        InputBuffer  = Irp->AssociatedIrp.SystemBuffer;
+        InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+
+        RDB = (PREPARSE_DATA_BUFFER)InputBuffer;
+        Status = Ext2InspectReparseData(RDB, InputBufferLength);
+        if (!NT_SUCCESS(Status)) {
+            _SEH2_LEAVE;
+        }
+
+        UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength;
+        UniName.MaximumLength = UniName.Length;
+        UniName.Buffer =
+            (PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer
+             + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+
+        OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName);
+        if (OemNameLength > USHRT_MAX) {
+            Status = STATUS_INVALID_PARAMETER;
+            _SEH2_LEAVE;
+        }
+        OemName.Length = (USHORT)OemNameLength;
+        OemName.MaximumLength = OemNameLength + 1;
+        OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool,
+                                          OemName.MaximumLength,
+                                          'NL2E');
+        if (!OemNameBuffer) {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            _SEH2_LEAVE;
+        }
+
+        Ext2UnicodeToOEM(Vcb, &OemName, &UniName);
+        OemName.Buffer[OemName.Length] = '\0';
+        for (i = 0;i < OemName.Length;i++) {
+            if (OemName.Buffer[i] == '\\') {
+                OemName.Buffer[i] = '/';
+            }
+        }
+
+        /* overwrite inode mode as type SYMLINK */
+        Mcb->Inode.i_mode = S_IFLNK | S_IRWXUGO;
+        Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+        SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+
+        Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
+                                  OemNameLength, &BytesWritten);
+        if (NT_SUCCESS(Status)) {
+            Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
+        }
+
+    } _SEH2_FINALLY {
+
+        if (MainResourceAcquired) {
+            ExReleaseResourceLite(&Fcb->MainResource);
+        }
+        
+        if (OemNameBuffer) {
+            Ext2FreePool(OemNameBuffer, 'NL2E');
+        }
+        
+        if (NT_SUCCESS(Status)) {
+            Ext2NotifyReportChange(
+                IrpContext,
+                Vcb,
+                Mcb,
+                FILE_NOTIFY_CHANGE_ATTRIBUTES,
+                FILE_ACTION_MODIFIED );
+        }
+
+        if (bNewParentDcb) {
+            ASSERT(ParentDcb != NULL);
+            if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
+                Ext2FreeFcb(ParentDcb);
+                ParentDcb = NULL;
+            } else {
+                DEBUG(DL_RES, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
+            }
+        }
+
+        if (!_SEH2_AbnormalTermination()) {
+            if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+                Status = Ext2QueueRequest(IrpContext);
+            } else {
+                Ext2CompleteIrpContext(IrpContext, Status);
+            }
+        }
+    } _SEH2_END;
+    
+    return Status;
+}
+
+NTSTATUS
+Ext2TruncateSymlink(
+    PEXT2_IRP_CONTEXT IrpContext,
+    PEXT2_VCB         Vcb,
+    PEXT2_MCB         Mcb,
+    ULONG             Size
+    )
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    PUCHAR   data = (PUCHAR)&Mcb->Inode.i_block;
+    ULONG    len = (ULONG)Mcb->Inode.i_size;
+    LARGE_INTEGER NewSize;
+    
+    if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
+
+        RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
+        Mcb->Inode.i_size = Size;
+        Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+
+    } else {
+        NewSize.QuadPart = Size;
+        status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
+        if (!NT_SUCCESS(status)) {
+            goto out;
+        }
+    }
+    
+out:
+    return status;
+}
+
+
+/* FIXME: We can only handle one reparse point right now. */
+NTSTATUS
+Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+    PIRP                        Irp = NULL;
+
+    PDEVICE_OBJECT      DeviceObject;
+
+    PEXT2_VCB           Vcb = NULL;
+    PEXT2_FCB           Fcb = NULL;
+    PEXT2_CCB           Ccb = NULL;
+    PEXT2_MCB           Mcb = NULL;
+
+    NTSTATUS            Status = STATUS_UNSUCCESSFUL;
+    BOOLEAN             bNewParentDcb = FALSE;
+    BOOLEAN             bFcbAllocated = FALSE;
+    BOOLEAN             MainResourceAcquired = FALSE;
+    
+    PEXT2_FCB           ParentDcb = NULL;   /* Dcb of it's current parent */
+    PEXT2_MCB           ParentMcb = NULL;
+
+    _SEH2_TRY {
+
+        Ccb = IrpContext->Ccb;
+        ASSERT(Ccb != NULL);
+        ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+               (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+        DeviceObject = IrpContext->DeviceObject;
+        Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+        Mcb = IrpContext->Fcb->Mcb;
+        Irp = IrpContext->Irp;
+
+        ParentMcb = Mcb->Parent;
+        ParentDcb = ParentMcb->Fcb;
+        if (ParentDcb == NULL) {
+            ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+            if (ParentDcb) {
+                Ext2ReferXcb(&ParentDcb->ReferenceCount);
+                bNewParentDcb = TRUE;
+            }
+        }
+
+        if (!Mcb) {
+            Status = STATUS_NOT_A_REPARSE_POINT;
+            _SEH2_LEAVE;
+        }
+        
+        Fcb = Ext2AllocateFcb (Vcb, Mcb);
+        if (Fcb) {
+            bFcbAllocated = TRUE;
+        } else {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            _SEH2_LEAVE;
+        }
+        Ext2ReferXcb(&Fcb->ReferenceCount);
+
+        if (!ExAcquireResourceSharedLite(
+                    &Fcb->MainResource,
+                    IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+            Status = STATUS_PENDING;
+            _SEH2_LEAVE;
+        }
+        MainResourceAcquired = TRUE;
+
+        Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
+        if (!NT_SUCCESS(Status)) {
+            _SEH2_LEAVE;
+        }
+        if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+            SetFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+        }
+        ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+        ClearFlag(Mcb->Inode.i_flags, S_IFLNK);
+        Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+        if (NT_SUCCESS(Status)) {
+            Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
+        }
+
+    } _SEH2_FINALLY {
+
+        if (MainResourceAcquired) {
+            ExReleaseResourceLite(&Fcb->MainResource);
+        }
+        
+        if (NT_SUCCESS(Status)) {
+            Ext2NotifyReportChange(
+                IrpContext,
+                Vcb,
+                Mcb,
+                FILE_NOTIFY_CHANGE_ATTRIBUTES,
+                FILE_ACTION_MODIFIED );
+
+        }
+        
+        if (bNewParentDcb) {
+            ASSERT(ParentDcb != NULL);
+            if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
+                Ext2FreeFcb(ParentDcb);
+                ParentDcb = NULL;
+            } else {
+                DEBUG(DL_RES, ( "Ext2DeleteReparsePoint: ParentDcb is resued.\n"));
+            }
+        }
+
+        if (!_SEH2_AbnormalTermination()) {
+            if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+                Status = Ext2QueueRequest(IrpContext);
+            } else {
+                Ext2CompleteIrpContext(IrpContext, Status);
+            }
+        }
+        
+        if (bFcbAllocated) {
+            if (Ext2DerefXcb(&Fcb->ReferenceCount) == 0) {
+                Ext2FreeFcb(Fcb);
+            }
+        }
+    } _SEH2_END;
+    
+    return Status;
+}
 
 NTSTATUS
 Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
@@ -1304,7 +1893,6 @@ Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
 
     Irp = IrpContext->Irp;
-
     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
 
 #ifndef _GNU_NTIFS_
@@ -1317,6 +1905,18 @@ Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
 
     switch (FsControlCode) {
 
+    case FSCTL_GET_REPARSE_POINT:
+        Status = Ext2GetReparsePoint(IrpContext);
+        break;
+        
+    case FSCTL_SET_REPARSE_POINT:
+        Status = Ext2SetReparsePoint(IrpContext);
+        break;
+        
+    case FSCTL_DELETE_REPARSE_POINT:
+        Status = Ext2DeleteReparsePoint(IrpContext);
+        break;
+
     case FSCTL_LOCK_VOLUME:
         Status = Ext2LockVolume(IrpContext);
         break;
@@ -1513,6 +2113,10 @@ Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
         VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
         ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
 
+/*
+        These are for buffer-address alignment requirements.
+        Never do this check, unless you want fail user requests :)
+
         if (TargetDeviceObject->AlignmentRequirement >
                 VolumeDeviceObject->AlignmentRequirement) {
 
@@ -1520,6 +2124,14 @@ Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
                 TargetDeviceObject->AlignmentRequirement;
         }
 
+        if (DiskGeometry.BytesPerSector - 1 >
+                VolumeDeviceObject->AlignmentRequirement) {
+            VolumeDeviceObject->AlignmentRequirement =
+                DiskGeometry.BytesPerSector - 1;
+            TargetDeviceObject->AlignmentRequirement =
+                DiskGeometry.BytesPerSector - 1;
+        }
+*/
         (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
             VolumeDeviceObject;
         Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
@@ -1891,7 +2503,7 @@ Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     PDEVICE_OBJECT  DeviceObject;
     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
-    PEXT2_VCB       Vcb;
+    PEXT2_VCB       Vcb = NULL;
     BOOLEAN         VcbResourceAcquired = FALSE;
 
     _SEH2_TRY {
@@ -1968,11 +2580,12 @@ Ext2CheckDismount (
     BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
     ULONG   UnCleanCount = 0;
 
-    NewVpb = Ext2AllocatePool(NonPagedPool, VPB_SIZE, TAG_VPB);
+    NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB);
     if (NewVpb == NULL) {
         DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
         return FALSE;
     }
+    DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb));
     INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
     memset(NewVpb, '_', VPB_SIZE);
     RtlZeroMemory(NewVpb, sizeof(VPB));
@@ -1985,15 +2598,16 @@ Ext2CheckDismount (
 
     if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
             (IrpContext->RealDevice == Vcb->RealDevice)) {
-        UnCleanCount = 3;
-    } else {
         UnCleanCount = 2;
+    } else {
+        UnCleanCount = 1;
     }
 
     IoAcquireVpbSpinLock (&Irql);
 
     DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
                    Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
+
     if (Vpb->ReferenceCount <= UnCleanCount) {
 
         if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
@@ -2018,10 +2632,17 @@ Ext2CheckDismount (
             Vpb->DeviceObject = NULL;
         }
 
+        DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n",
+                        Vpb, bDeleted, bTearDown));
+
+
     } else if (bForce) {
 
-        DEBUG(DL_DBG, ( "Ext2CheckDismount: NewVpb %p Realdevice = %p\n",
-                        NewVpb, Vpb->RealDevice));
+        DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n",
+                        NewVpb, Vcb->Vpb, Vpb->RealDevice));
+
+        /* keep vpb president and later we'll free it */
+        SetFlag(Vpb->Flags, VPB_PERSISTENT);
 
         Vcb->Vpb2 = Vcb->Vpb;
         NewVpb->Type = IO_TYPE_VPB;
@@ -2051,8 +2672,8 @@ Ext2CheckDismount (
     }
 
     if (NewVpb != NULL) {
-        DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing Vpb %p\n", NewVpb));
-        Ext2FreePool(NewVpb, TAG_VPB);
+        DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb));
+        ExFreePoolWithTag(NewVpb, TAG_VPB);
         DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
     }
 
@@ -2081,8 +2702,6 @@ Ext2PurgeVolume (IN PEXT2_VCB Vcb,
             FlushBeforePurge = FALSE;
         }
 
-        Ext2PutGroup(Vcb);
-
         FcbListEntry= NULL;
         InitializeListHead(&FcbList);
 
index 4a40e2d..470811a 100644 (file)
@@ -18,10 +18,12 @@ PEXT2_GLOBAL    Ext2Global   = NULL;
 /*
  *   Ext2Fsd version, building date/time
  */
+
 CHAR            gVersion[]   = EXT2FSD_VERSION;
 CHAR            gTime[] = __TIME__;
 CHAR            gDate[] = __DATE__;
 
+
 /* DEFINITIONS ***********************************************************/
 
 NTSTATUS NTAPI
@@ -417,8 +419,8 @@ DriverEntry (
         " Free"
 #endif
         " -- "
-        __DATE__" "
-        __TIME__".\n");
+        __DATE__ " "
+        __TIME__ ".\n");
 
     DEBUG(DL_FUN, ( "Ext2 DriverEntry ...\n"));
 
index f0df577..2835ed2 100644 (file)
@@ -43,9 +43,9 @@ int log_start_commit(journal_t *journal, tid_t tid)
 {
     int ret;
 
-    spin_lock(&journal->j_state_lock);
+    jbd_lock(&journal->j_state_lock);
     ret = __log_start_commit(journal, tid);
-    spin_unlock(&journal->j_state_lock);
+    jbd_unlock(&journal->j_state_lock);
     return ret;
 }
 
@@ -69,12 +69,12 @@ static void __journal_abort_hard(journal_t *journal)
     if (journal->j_flags & JFS_ABORT)
         return;
 
-    spin_lock(&journal->j_state_lock);
+    jbd_lock(&journal->j_state_lock);
     journal->j_flags |= JFS_ABORT;
     transaction = journal->j_running_transaction;
     if (transaction)
         __log_start_commit(journal, transaction->t_tid);
-    spin_unlock(&journal->j_state_lock);
+    jbd_unlock(&journal->j_state_lock);
 }
 
 /* Soft abort: record the abort error status in the journal superblock,
@@ -160,12 +160,12 @@ int journal_errno(journal_t *journal)
 {
     int err;
 
-    spin_lock(&journal->j_state_lock);
+    jbd_lock(&journal->j_state_lock);
     if (journal->j_flags & JFS_ABORT)
         err = -EROFS;
     else
         err = journal->j_errno;
-    spin_unlock(&journal->j_state_lock);
+    jbd_unlock(&journal->j_state_lock);
     return err;
 }
 
@@ -180,12 +180,12 @@ int journal_clear_err(journal_t *journal)
 {
     int err = 0;
 
-    spin_lock(&journal->j_state_lock);
+    jbd_lock(&journal->j_state_lock);
     if (journal->j_flags & JFS_ABORT)
         err = -EROFS;
     else
         journal->j_errno = 0;
-    spin_unlock(&journal->j_state_lock);
+    jbd_unlock(&journal->j_state_lock);
     return err;
 }
 
@@ -198,10 +198,10 @@ int journal_clear_err(journal_t *journal)
  */
 void journal_ack_err(journal_t *journal)
 {
-    spin_lock(&journal->j_state_lock);
+    jbd_lock(&journal->j_state_lock);
     if (journal->j_errno)
         journal->j_flags |= JFS_ACK_ERR;
-    spin_unlock(&journal->j_state_lock);
+    jbd_unlock(&journal->j_state_lock);
 }
 
 int journal_blocks_per_page(struct inode *inode)
@@ -462,7 +462,7 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp)
 {
     unsigned long blocknr;
 
-    spin_lock(&journal->j_state_lock);
+    jbd_lock(&journal->j_state_lock);
     J_ASSERT(journal->j_free > 1);
 
     blocknr = journal->j_head;
@@ -470,7 +470,7 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp)
     journal->j_free--;
     if (journal->j_head == journal->j_last)
         journal->j_head = journal->j_first;
-    spin_unlock(&journal->j_state_lock);
+    jbd_unlock(&journal->j_state_lock);
     return journal_bmap(journal, blocknr, retp);
 }
 
@@ -561,9 +561,9 @@ static journal_t * journal_init_common (void)
     init_waitqueue_head(&journal->j_wait_updates);
     mutex_init(&journal->j_barrier);
     mutex_init(&journal->j_checkpoint_mutex);
-    spin_lock_init(&journal->j_revoke_lock);
-    spin_lock_init(&journal->j_list_lock);
-    spin_lock_init(&journal->j_state_lock);
+    jbd_lock_init(&journal->j_revoke_lock);
+    jbd_lock_init(&journal->j_list_lock);
+    jbd_lock_init(&journal->j_state_lock);
 
     journal->j_commit_interval = (HZ * JBD_DEFAULT_MAX_COMMIT_AGE);
 
@@ -688,17 +688,17 @@ void journal_destroy(journal_t *journal)
     /* Force any old transactions to disk */
 
     /* Totally anal locking here... */
-    spin_lock(&journal->j_list_lock);
+    jbd_lock(&journal->j_list_lock);
     while (journal->j_checkpoint_transactions != NULL) {
-        spin_unlock(&journal->j_list_lock);
+        jbd_unlock(&journal->j_list_lock);
         log_do_checkpoint(journal);
-        spin_lock(&journal->j_list_lock);
+        jbd_lock(&journal->j_list_lock);
     }
 
     J_ASSERT(journal->j_running_transaction == NULL);
     J_ASSERT(journal->j_committing_transaction == NULL);
     J_ASSERT(journal->j_checkpoint_transactions == NULL);
-    spin_unlock(&journal->j_list_lock);
+    jbd_unlock(&journal->j_list_lock);
 
     /* We can now mark the journal as empty. */
     journal->j_tail = 0;
@@ -1048,14 +1048,14 @@ void journal_update_superblock(journal_t *journal, int wait)
         goto out;
     }
 
-    spin_lock(&journal->j_state_lock);
+    jbd_lock(&journal->j_state_lock);
     jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
               journal->j_tail, journal->j_tail_sequence, journal->j_errno);
 
     sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);
     sb->s_start    = cpu_to_be32(journal->j_tail);
     sb->s_errno    = cpu_to_be32(journal->j_errno);
-    spin_unlock(&journal->j_state_lock);
+    jbd_unlock(&journal->j_state_lock);
 
     BUFFER_TRACE(bh, "marking dirty");
     mark_buffer_dirty(bh);
@@ -1069,12 +1069,12 @@ out:
      * any future commit will have to be careful to update the
      * superblock again to re-record the true start of the log. */
 
-    spin_lock(&journal->j_state_lock);
+    jbd_lock(&journal->j_state_lock);
     if (sb->s_start)
         journal->j_flags &= ~JFS_FLUSHED;
     else
         journal->j_flags |= JFS_FLUSHED;
-    spin_unlock(&journal->j_state_lock);
+    jbd_unlock(&journal->j_state_lock);
 }
 
 /*
@@ -1240,7 +1240,7 @@ static void __journal_temp_unlink_buffer(struct journal_head *jh)
     J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
     transaction = jh->b_transaction;
     if (transaction)
-        assert_spin_locked(&transaction->t_journal->j_list_lock);
+        assert_jbd_locked(&transaction->t_journal->j_list_lock);
 
     J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
     if (jh->b_jlist != BJ_None)
@@ -1292,9 +1292,9 @@ void __journal_unfile_buffer(struct journal_head *jh)
 void journal_unfile_buffer(journal_t *journal, struct journal_head *jh)
 {
     jbd_lock_bh_state(jh2bh(jh));
-    spin_lock(&journal->j_list_lock);
+    jbd_lock(&journal->j_list_lock);
     __journal_unfile_buffer(jh);
-    spin_unlock(&journal->j_list_lock);
+    jbd_unlock(&journal->j_list_lock);
     jbd_unlock_bh_state(jh2bh(jh));
 }
 
@@ -1342,7 +1342,7 @@ void __journal_file_buffer(struct journal_head *jh,
     struct buffer_head *bh = jh2bh(jh);
 
     J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
-    assert_spin_locked(&transaction->t_journal->j_list_lock);
+    assert_jbd_locked(&transaction->t_journal->j_list_lock);
 
     J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
     J_ASSERT_JH(jh, jh->b_transaction == transaction ||
@@ -1409,9 +1409,9 @@ void journal_file_buffer(struct journal_head *jh,
                          transaction_t *transaction, int jlist)
 {
     jbd_lock_bh_state(jh2bh(jh));
-    spin_lock(&transaction->t_journal->j_list_lock);
+    jbd_lock(&transaction->t_journal->j_list_lock);
     __journal_file_buffer(jh, transaction, jlist);
-    spin_unlock(&transaction->t_journal->j_list_lock);
+    jbd_unlock(&transaction->t_journal->j_list_lock);
     jbd_unlock_bh_state(jh2bh(jh));
 }
 
@@ -1455,7 +1455,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
     BUFFER_TRACE(bh, "entry");
 
     jbd_lock_bh_state(bh);
-    spin_lock(&journal->j_list_lock);
+    jbd_lock(&journal->j_list_lock);
 
     if (!buffer_jbd(bh))
         goto not_jbd;
@@ -1508,7 +1508,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
             journal_remove_journal_head(bh);
             __brelse(bh);
             if (!buffer_jbd(bh)) {
-                spin_unlock(&journal->j_list_lock);
+                jbd_unlock(&journal->j_list_lock);
                 jbd_unlock_bh_state(bh);
                 __bforget(bh);
                 goto drop;
@@ -1531,7 +1531,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
     }
 
 not_jbd:
-    spin_unlock(&journal->j_list_lock);
+    jbd_unlock(&journal->j_list_lock);
     jbd_unlock_bh_state(bh);
     __brelse(bh);
 drop:
index 2689283..0ba861a 100644 (file)
@@ -131,9 +131,9 @@ repeat:
     record->sequence = seq;
     record->blocknr = blocknr;
     hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
-    spin_lock(&journal->j_revoke_lock);
+    jbd_lock(&journal->j_revoke_lock);
     list_add(&record->hash, hash_list);
-    spin_unlock(&journal->j_revoke_lock);
+    jbd_unlock(&journal->j_revoke_lock);
     return 0;
 
 oom:
@@ -154,16 +154,16 @@ static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal,
 
     hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
 
-    spin_lock(&journal->j_revoke_lock);
+    jbd_lock(&journal->j_revoke_lock);
     record = (struct jbd_revoke_record_s *) hash_list->next;
     while (&(record->hash) != hash_list) {
         if (record->blocknr == blocknr) {
-            spin_unlock(&journal->j_revoke_lock);
+            jbd_unlock(&journal->j_revoke_lock);
             return record;
         }
         record = (struct jbd_revoke_record_s *) record->hash.next;
     }
-    spin_unlock(&journal->j_revoke_lock);
+    jbd_unlock(&journal->j_revoke_lock);
     return NULL;
 }
 
@@ -261,7 +261,7 @@ int journal_init_revoke(journal_t *journal, int hash_size)
     for (tmp = 0; tmp < hash_size; tmp++)
         INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
 
-    spin_lock_init(&journal->j_revoke_lock);
+    jbd_lock_init(&journal->j_revoke_lock);
 
     return 0;
 }
@@ -447,9 +447,9 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
         if (record) {
             jbd_debug(4, "cancelled existing revoke on "
                       "blocknr %llu\n", (u64)bh->b_blocknr);
-            spin_lock(&journal->j_revoke_lock);
+            jbd_lock(&journal->j_revoke_lock);
             list_del(&record->hash);
-            spin_unlock(&journal->j_revoke_lock);
+            jbd_unlock(&journal->j_revoke_lock);
             kmem_cache_free(revoke_record_cache, record);
             did_revoke = 1;
         }
index 889bf09..289c0c7 100644 (file)
@@ -353,6 +353,10 @@ free_buffer_head(struct buffer_head * bh)
 
             Ext2DestroyMdl(bh->b_mdl);
         }
+        if (bh->b_bcb) {
+            CcUnpinDataForThread(bh->b_bcb, (ERESOURCE_THREAD)bh | 0x3);
+        }
+
         DEBUG(DL_BH, ("bh=%p freed.\n", bh));
         DEC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head));
         kmem_cache_free(g_jbh.bh_cache, bh);
@@ -420,7 +424,7 @@ static void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh
 }
 
 struct buffer_head *
-get_block_bh(
+get_block_bh_mdl(
     struct block_device *   bdev,
     sector_t                block,
     unsigned long           size,
@@ -538,17 +542,7 @@ errorout:
     return bh;
 }
 
-struct buffer_head *
-__getblk(
-    struct block_device *   bdev,
-    sector_t                block,
-    unsigned long           size
-)
-{
-    return get_block_bh(bdev, block, size, 0);
-}
-
-int submit_bh(int rw, struct buffer_head *bh)
+int submit_bh_mdl(int rw, struct buffer_head *bh)
 {
     struct block_device *bdev = bh->b_bdev;
     PEXT2_VCB            Vcb  = bdev->bd_priv;
@@ -607,6 +601,159 @@ errorout:
     return 0;
 }
 
+struct buffer_head *
+get_block_bh(
+    struct block_device *   bdev,
+    sector_t                block,
+    unsigned long           size,
+    int                     zero
+) 
+{
+    PEXT2_VCB Vcb = bdev->bd_priv;
+    LARGE_INTEGER offset;
+
+    KIRQL irql = 0;
+    struct list_head *entry;
+
+    /* allocate buffer_head and initialize it */
+    struct buffer_head *bh = NULL, *tbh = NULL;
+
+    /* check the block is valid or not */
+    if (block >= TOTAL_BLOCKS) {
+        DbgBreak();
+        goto errorout;
+    }
+
+    /* search the bdev bh list */
+    spin_lock_irqsave(&bdev->bd_bh_lock, irql);
+    tbh = buffer_head_search(bdev, block);
+    if (tbh) {
+        bh = tbh;
+        get_bh(bh);
+        spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+        goto errorout;
+    }
+    spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+
+    bh = new_buffer_head();
+    if (!bh) {
+        goto errorout;
+    }
+    bh->b_bdev = bdev;
+    bh->b_blocknr = block;
+    bh->b_size = size;
+    bh->b_data = NULL;
+    atomic_inc(&g_jbh.bh_count);
+    atomic_inc(&g_jbh.bh_acount);
+
+again:
+
+    offset.QuadPart = (s64) bh->b_blocknr;
+    offset.QuadPart <<= BLOCK_BITS;
+
+    if (zero) {
+        if (!CcPreparePinWrite(Vcb->Volume,
+                            &offset,
+                            bh->b_size,
+                            FALSE,
+                            PIN_WAIT | PIN_EXCLUSIVE,
+                            &bh->b_bcb,
+                            (PVOID *)&bh->b_data)) {
+            Ext2Sleep(100);
+            goto again;
+        }
+    } else {
+        if (!CcPinRead( Vcb->Volume,
+                        &offset,
+                        bh->b_size,
+                        PIN_WAIT,
+                        &bh->b_bcb,
+                        (PVOID *)&bh->b_data)) {
+            Ext2Sleep(100);
+            goto again;
+        }
+        set_buffer_uptodate(bh);
+    }
+
+    if (!bh->b_data) {
+        free_buffer_head(bh);
+        bh = NULL;
+        goto errorout;
+    }
+
+    get_bh(bh);
+    CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3));
+
+    DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p ptr=%p.\n",
+                  Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_data));
+
+    spin_lock_irqsave(&bdev->bd_bh_lock, irql);
+
+    /* do search again here */
+    tbh = buffer_head_search(bdev, block);
+    if (tbh) {
+        get_bh(tbh);
+        spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+        free_buffer_head(bh);
+        bh = tbh;
+        goto errorout;
+    } else {
+        buffer_head_insert(bdev, bh);
+    }
+
+    spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+
+    /* we get it */
+errorout:
+
+    return bh;
+}
+
+int submit_bh(int rw, struct buffer_head *bh)
+{
+    struct block_device *bdev = bh->b_bdev;
+    PEXT2_VCB            Vcb  = bdev->bd_priv;
+    PVOID                Buffer;
+    LARGE_INTEGER        Offset;
+
+    ASSERT(Vcb->Identifier.Type == EXT2VCB);
+    ASSERT(bh->b_data && bh->b_bcb);
+
+    if (rw == WRITE) {
+
+        if (IsVcbReadOnly(Vcb)) {
+            goto errorout;
+        }
+
+        SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
+        Offset.QuadPart = ((LONGLONG)bh->b_blocknr) << BLOCK_BITS;
+
+        CcSetDirtyPinnedData(bh->b_bcb, NULL);
+        Ext2AddBlockExtent( Vcb, NULL,
+                            (ULONG)bh->b_blocknr,
+                            (ULONG)bh->b_blocknr,
+                            (bh->b_size >> BLOCK_BITS));
+    } else {
+        DbgBreak();
+    }
+
+errorout:
+
+    unlock_buffer(bh);
+    put_bh(bh);
+    return 0;
+}
+
+struct buffer_head *
+__getblk(
+    struct block_device *   bdev,
+    sector_t                block,
+    unsigned long           size
+)
+{
+    return get_block_bh(bdev, block, size, 0);
+}
+
 void __brelse(struct buffer_head *bh)
 {
     struct block_device *bdev = bh->b_bdev;
@@ -636,6 +783,7 @@ void __brelse(struct buffer_head *bh)
     atomic_dec(&g_jbh.bh_count);
 }
 
+
 void __bforget(struct buffer_head *bh)
 {
     clear_buffer_dirty(bh);
index 82d15a8..640162a 100644 (file)
@@ -24,10 +24,10 @@ extern PEXT2_GLOBAL Ext2Global;
 NTSTATUS
 Ext2LockControl (IN PEXT2_IRP_CONTEXT IrpContext)
 {
-    PDEVICE_OBJECT  DeviceObject;
-    PFILE_OBJECT    FileObject;
-    PEXT2_FCB       Fcb;
-    PIRP            Irp;
+    PDEVICE_OBJECT  DeviceObject = NULL;
+    PFILE_OBJECT    FileObject = NULL;
+    PEXT2_FCB       Fcb = NULL;
+    PIRP            Irp = NULL;
 
     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
     BOOLEAN         CompleteContext = TRUE;
index 37129c2..da91dc1 100644 (file)
@@ -138,8 +138,6 @@ Ext2AllocateFcb (
 {
     PEXT2_FCB Fcb;
 
-    ASSERT(!IsMcbSymLink(Mcb));
-
     Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
               &(Ext2Global->Ext2FcbLookasideList));
 
@@ -216,7 +214,7 @@ Ext2FreeFcb (IN PEXT2_FCB Fcb)
 #endif
 
     if ((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
-            (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
+        (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
 
         ASSERT (Fcb->Mcb->Fcb == Fcb);
         if (IsMcbSpecialFile(Fcb->Mcb) || IsFileDeleted(Fcb->Mcb)) {
@@ -283,7 +281,7 @@ Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
 }
 
 PEXT2_CCB
-Ext2AllocateCcb (PEXT2_MCB  SymLink)
+Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink)
 {
     PEXT2_CCB Ccb;
 
@@ -299,6 +297,7 @@ Ext2AllocateCcb (PEXT2_MCB  SymLink)
 
     Ccb->Identifier.Type = EXT2CCB;
     Ccb->Identifier.Size = sizeof(EXT2_CCB);
+    Ccb->Flags = Flags;
 
     Ccb->SymLink = SymLink;
     if (SymLink) {
@@ -1187,7 +1186,7 @@ Ext2BuildExtents(
     NTSTATUS    Status = STATUS_SUCCESS;
 
     PEXT2_EXTENT  Extent = NULL;
-    PEXT2_EXTENT  List = *Chain;
+    PEXT2_EXTENT  List = *Chain = NULL;
 
     if (!IsZoneInited(Mcb)) {
         Status = Ext2InitializeZone(IrpContext, Vcb, Mcb);
@@ -1246,7 +1245,7 @@ Ext2BuildExtents(
                              &Mapped
                      );
             if (!NT_SUCCESS(Status)) {
-                goto errorout;
+                break;
             }
 
             /* skip wrong blocks, in case wrongly treating symlink
@@ -1272,6 +1271,11 @@ Ext2BuildExtents(
             Length = Size;
         }
 
+        if (0 == Length) {
+            DbgBreak();
+            break;
+        }
+
         Start += Mapped;
         Offset = (ULONGLONG)Start << BLOCK_BITS;
 
@@ -1288,7 +1292,8 @@ Ext2BuildExtents(
                 Extent = Ext2AllocateExtent();
                 if (!Extent) {
                     Status = STATUS_INSUFFICIENT_RESOURCES;
-                    goto errorout;
+                    DbgBreak();
+                    break;
                 }
 
                 Extent->Lba = Lba;
@@ -1303,14 +1308,16 @@ Ext2BuildExtents(
                     *Chain = List = Extent;
                 }
             }
+        } else {
+            if (bAlloc) {
+                DbgBreak();
+            }
         }
 
         Total += Length;
         Size  -= Length;
     }
 
-errorout:
-
     return Status;
 }
 
@@ -1800,29 +1807,23 @@ Ext2CleanupAllMcbs(PEXT2_VCB Vcb)
 BOOLEAN
 Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
 {
-    PEXT2_GROUP_DESC gd;
-    ULONG           Group, dwBlk, Length;
-
-    RTL_BITMAP      BlockBitmap;
-    PVOID           BitmapCache;
-    PBCB            BitmapBcb;
-
-    LARGE_INTEGER   Offset;
-
-    BOOLEAN         bModified = FALSE;
-
-
-    Group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
+    PEXT2_GROUP_DESC    gd;
+    struct buffer_head *gb = NULL;
+    struct buffer_head *bh = NULL;
+    ULONG               group, dwBlk, Length;
+    RTL_BITMAP          bitmap;
+    BOOLEAN             bModified = FALSE;
+
+    group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
     dwBlk = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
 
-    gd = ext4_get_group_desc(&Vcb->sb, Group, NULL);
+    gd = ext4_get_group_desc(&Vcb->sb, group, &gb);
     if (!gd) {
         return FALSE;
     }
-    Offset.QuadPart = ext4_block_bitmap(&Vcb->sb, gd);
-    Offset.QuadPart <<= BLOCK_BITS;
+    bh = sb_getblk(&Vcb->sb, ext4_block_bitmap(&Vcb->sb, gd));
 
-    if (Group == Vcb->sbi.s_groups_count - 1) {
+    if (group == Vcb->sbi.s_groups_count - 1) {
         Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
 
         /* s_blocks_count is integer multiple of s_blocks_per_group */
@@ -1832,43 +1833,23 @@ Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
         Length = BLOCKS_PER_GROUP;
     }
 
-    if (dwBlk >= Length)
-        return FALSE;
-
-    if (!CcPinRead( Vcb->Volume,
-                    &Offset,
-                    Vcb->BlockSize,
-                    PIN_WAIT,
-                    &BitmapBcb,
-                    &BitmapCache ) ) {
-
-        DEBUG(DL_ERR, ( "Ext2CheckSetBlock: Failed to PinLock block %xh ...\n",
-                        ext4_block_bitmap(&Vcb->sb, gd)));
+    if (dwBlk >= Length) {
+        fini_bh(&gb);
+        fini_bh(&bh);
         return FALSE;
     }
 
-    RtlInitializeBitMap( &BlockBitmap,
-                         BitmapCache,
-                         Length );
+    RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
 
-    if (RtlCheckBit(&BlockBitmap, dwBlk) == 0) {
+    if (RtlCheckBit(&bitmap, dwBlk) == 0) {
         DbgBreak();
-        RtlSetBits(&BlockBitmap, dwBlk, 1);
+        RtlSetBits(&bitmap, dwBlk, 1);
         bModified = TRUE;
+        mark_buffer_dirty(bh);
     }
 
-    if (bModified) {
-        CcSetDirtyPinnedData(BitmapBcb, NULL );
-        Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE);
-    }
-
-    {
-        CcUnpinData(BitmapBcb);
-        BitmapBcb = NULL;
-        BitmapCache = NULL;
-
-        RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
-    }
+    fini_bh(&gb);
+    fini_bh(&bh);
 
     return (!bModified);
 }
@@ -1881,8 +1862,9 @@ Ext2CheckBitmapConsistency(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
     for (i = 0; i < Vcb->sbi.s_groups_count; i++) {
 
         PEXT2_GROUP_DESC    gd;
+        struct buffer_head  *bh = NULL;
 
-        gd = ext4_get_group_desc(&Vcb->sb, i, NULL);
+        gd = ext4_get_group_desc(&Vcb->sb, i, &bh);
         if (!gd)
             continue;
         Ext2CheckSetBlock(IrpContext, Vcb, ext4_block_bitmap(&Vcb->sb, gd));
@@ -1900,6 +1882,8 @@ Ext2CheckBitmapConsistency(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
 
         for (j = 0; j < InodeBlocks; j++ )
             Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_table(&Vcb->sb, gd) + j);
+
+        fini_bh(&bh);
     }
 
     return TRUE;
@@ -2687,7 +2671,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
             }
 
             if (ExtentsInitialized) {
-                Ext2PutGroup(Vcb);
+                Ext2DropGroup(Vcb);
                 if (Vcb->bd.bd_bh_cache)
                     kmem_cache_destroy(Vcb->bd.bd_bh_cache);
                 FsRtlUninitializeLargeMcb(&(Vcb->Extents));
@@ -2764,7 +2748,7 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb)
 
     Ext2CleanupAllMcbs(Vcb);
 
-    Ext2PutGroup(Vcb);
+    Ext2DropGroup(Vcb);
 
     if (Vcb->bd.bd_bh_cache)
         kmem_cache_destroy(Vcb->bd.bd_bh_cache);
@@ -2776,7 +2760,8 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb)
 
     if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
         ASSERT(Vcb->Vpb2 != NULL);
-        Ext2FreePool(Vcb->Vpb2, TAG_VPB);
+        DEBUG(DL_DBG, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb->Vpb2));
+        ExFreePoolWithTag(Vcb->Vpb2, TAG_VPB);
         DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
         Vcb->Vpb2 = NULL;
     }
index 1fbbc34..8f26a34 100644 (file)
@@ -382,10 +382,13 @@ int Ext2LinuxError (NTSTATUS Status)
     case STATUS_HOST_UNREACHABLE:
         return (-EHOSTUNREACH);
 
+    case STATUS_CANT_WAIT:
     case STATUS_PENDING:
-    case STATUS_DEVICE_NOT_READY:
         return (-EAGAIN);
 
+    case STATUS_DEVICE_NOT_READY:
+        return (-EIO);
+
     case STATUS_CANCELLED:
     case STATUS_REQUEST_ABORTED:
         return (-EINTR);
@@ -503,7 +506,7 @@ NTSTATUS Ext2WinntError(int rc)
         return STATUS_HOST_UNREACHABLE;
 
     case -EAGAIN:
-        return STATUS_DEVICE_NOT_READY;
+        return STATUS_CANT_WAIT;
 
     case -EINTR:
         return  STATUS_CANCELLED;
@@ -527,4 +530,4 @@ BOOLEAN Ext2IsDotDot(PUNICODE_STRING name)
 {
     return (name->Length == 4 && name->Buffer[0] == L'.' &&
             name->Buffer[1] == L'.');
-}
\ No newline at end of file
+}
index 82c26ad..1afb9f9 100644 (file)
@@ -63,7 +63,7 @@ Ext2Pnp (IN PEXT2_IRP_CONTEXT IrpContext)
 
     PIRP                Irp;
     PIO_STACK_LOCATION  IrpSp;
-    PEXT2_VCB           Vcb;
+    PEXT2_VCB           Vcb = NULL;
     PDEVICE_OBJECT      DeviceObject;
 
     _SEH2_TRY {
@@ -394,4 +394,4 @@ Ext2PnpCancelRemove (
     return Status;
 }
 
-#endif //(_WIN32_WINNT >= 0x0500)
\ No newline at end of file
+#endif //(_WIN32_WINNT >= 0x0500)
index b78c754..660fd5d 100644 (file)
@@ -65,15 +65,15 @@ Ext2ReadVolume (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
 
-    PEXT2_VCB           Vcb;
-    PEXT2_CCB           Ccb;
-    PEXT2_FCBVCB        FcbOrVcb;
-    PFILE_OBJECT        FileObject;
+    PEXT2_VCB           Vcb = NULL;
+    PEXT2_CCB           Ccb = NULL;
+    PEXT2_FCBVCB        FcbOrVcb = NULL;
+    PFILE_OBJECT        FileObject = NULL;
 
-    PDEVICE_OBJECT      DeviceObject;
+    PDEVICE_OBJECT      DeviceObject = NULL;
 
     PIRP                Irp = NULL;
-    PIO_STACK_LOCATION  IoStackLocation;
+    PIO_STACK_LOCATION  IoStackLocation = NULL;
 
     ULONG               Length;
     LARGE_INTEGER       ByteOffset;
@@ -347,11 +347,9 @@ Ext2ReadInode (
 
 
         /* handle fast symlinks */
-        if (S_ISLNK(Mcb->Inode.i_mode) &&
-                Mcb->Inode.i_size < EXT2_LINKLEN_IN_INODE) {
+        if (S_ISLNK(Mcb->Inode.i_mode) && 0 == Mcb->Inode.i_blocks) {
 
             PUCHAR Data = (PUCHAR) (&Mcb->Inode.i_block[0]);
-
             if (!Buffer) {
                 Status = STATUS_INSUFFICIENT_RESOURCES;
                 _SEH2_LEAVE;
@@ -474,15 +472,15 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
 {
     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
 
-    PEXT2_VCB           Vcb;
-    PEXT2_FCB           Fcb;
-    PEXT2_CCB           Ccb;
-    PFILE_OBJECT        FileObject;
+    PEXT2_VCB           Vcb = NULL;
+    PEXT2_FCB           Fcb = NULL;
+    PEXT2_CCB           Ccb = NULL;
+    PFILE_OBJECT        FileObject = NULL;
 
-    PDEVICE_OBJECT      DeviceObject;
+    PDEVICE_OBJECT      DeviceObject = NULL;
 
-    PIRP                Irp;
-    PIO_STACK_LOCATION  IoStackLocation;
+    PIRP                Irp = NULL;
+    PIO_STACK_LOCATION  IoStackLocation = NULL;
 
     ULONG               Length;
     ULONG               ReturnedLength = 0;
@@ -534,6 +532,11 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
         DEBUG(DL_INF, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
                        &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));
 
+        if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
+            Status = STATUS_INVALID_DEVICE_REQUEST;
+            _SEH2_LEAVE;
+        }
+
         if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ||
             IsFileDeleted(Fcb->Mcb)) {
             Status = STATUS_FILE_DELETED;
@@ -546,9 +549,13 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
             _SEH2_LEAVE;
         }
 
-        if (Nocache &&
-                (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
-                 Length & (SECTOR_SIZE - 1))) {
+        if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
+            ByteOffset.HighPart == -1) {
+            ByteOffset = FileObject->CurrentByteOffset;
+        }
+
+        if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
+                        Length & (SECTOR_SIZE - 1))) {
             Status = STATUS_INVALID_PARAMETER;
             DbgBreak();
             _SEH2_LEAVE;
@@ -561,17 +568,6 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
             _SEH2_LEAVE;
         }
 
-        if (!PagingIo && Nocache && (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
-            CcFlushCache( FileObject->SectionObjectPointer,
-                          &ByteOffset,
-                          Length,
-                          &Irp->IoStatus );
-
-            if (!NT_SUCCESS(Irp->IoStatus.Status)) {
-                _SEH2_LEAVE;
-            }
-        }
-
         ReturnedLength = Length;
 
         if (PagingIo) {
@@ -596,6 +592,15 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
                 }
                 MainResourceAcquired = TRUE;
 
+                if (FileObject->SectionObjectPointer->DataSectionObject != NULL) {
+                    CcFlushCache( FileObject->SectionObjectPointer,
+                                 &ByteOffset,
+                                  Length,
+                                 &Irp->IoStatus );
+                    if (!NT_SUCCESS(Irp->IoStatus.Status))
+                        _SEH2_LEAVE;
+                }
+
             } else {
 
                 if (!ExAcquireResourceSharedLite(
index 895da8f..8840482 100644 (file)
@@ -27,13 +27,13 @@ NTSTATUS
 Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     PDEVICE_OBJECT          DeviceObject;
+    PEXT2_VCB               Vcb = NULL;
+    PIRP                    Irp = NULL;
+    PIO_STACK_LOCATION      IoStackLocation = NULL;
+    PVOID                   Buffer;
+    ULONG                   Length;
     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
-    PEXT2_VCB               Vcb;
-    PIRP                    Irp;
-    PIO_STACK_LOCATION      IoStackLocation;
     FS_INFORMATION_CLASS    FsInformationClass;
-    ULONG                   Length;
-    PVOID                   Buffer;
     BOOLEAN                 VcbResourceAcquired = FALSE;
 
     _SEH2_TRY {
@@ -186,8 +186,9 @@ Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
 
             FsAttrInfo =
                 (PFILE_FS_ATTRIBUTE_INFORMATION) Buffer;
-            FsAttrInfo->FileSystemAttributes =
-                FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
+            FsAttrInfo->FileSystemAttributes = FILE_SUPPORTS_HARD_LINKS |
+                FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
+                FILE_SUPPORTS_REPARSE_POINTS;
             if (IsVcbReadOnly(Vcb)) {
                 FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
             }
@@ -292,7 +293,7 @@ Ext2SetVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     PDEVICE_OBJECT          DeviceObject;
     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
-    PEXT2_VCB               Vcb;
+    PEXT2_VCB               Vcb = NULL;
     PIRP                    Irp;
     PIO_STACK_LOCATION      IoStackLocation;
     FS_INFORMATION_CLASS    FsInformationClass;
@@ -405,4 +406,4 @@ Ext2SetVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
     } _SEH2_END;
 
     return Status;
-}
\ No newline at end of file
+}
index fe50d34..a3ddcbc 100644 (file)
@@ -175,9 +175,8 @@ Ext2ZeroData (
     PBCB            Bcb;
     PVOID           Ptr;
     ULONG           Size;
-#ifndef __REACTOS__
     BOOLEAN         rc = TRUE;
-#endif
+
     ASSERT (End && Start && End->QuadPart > Start->QuadPart);
     Fcb = (PEXT2_FCB) FileObject->FsContext;
 
@@ -195,7 +194,13 @@ Ext2ZeroData (
     }
 
     /* clear data in range [Start, End) */
-    return CcZeroData(FileObject, Start, End, Ext2CanIWait());
+    _SEH2_TRY {
+        rc = CcZeroData(FileObject, Start, End, Ext2CanIWait());
+    } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+        DbgBreak();
+    } _SEH2_END;
+
+    return rc;
 }
 
 VOID
@@ -212,15 +217,15 @@ Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext)
 {
     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
 
-    PEXT2_VCB           Vcb;
-    PEXT2_CCB           Ccb;
-    PEXT2_FCBVCB        FcbOrVcb;
-    PFILE_OBJECT        FileObject;
+    PEXT2_VCB           Vcb = NULL;
+    PEXT2_CCB           Ccb = NULL;
+    PEXT2_FCBVCB        FcbOrVcb = NULL;
+    PFILE_OBJECT        FileObject = NULL;
 
-    PDEVICE_OBJECT      DeviceObject;
+    PDEVICE_OBJECT      DeviceObject = NULL;
 
     PIRP                Irp = NULL;
-    PIO_STACK_LOCATION  IoStackLocation;
+    PIO_STACK_LOCATION  IoStackLocation = NULL;
 
     ULONG               Length;
     LARGE_INTEGER       ByteOffset;
@@ -646,7 +651,7 @@ Ext2WriteInode (
     IN ULONG                Size,
     IN BOOLEAN              bDirectIo,
     OUT PULONG              BytesWritten
-)
+    )
 {
     PEXT2_EXTENT    Chain = NULL;
     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
@@ -663,7 +668,7 @@ Ext2WriteInode (
                      Mcb,
                      Offset,
                      Size,
-                     IsMcbDirectory(Mcb) ? FALSE : TRUE,
+                     S_ISDIR(Mcb->Inode.i_mode) ? FALSE : TRUE,
                      &Chain
                  );
 
@@ -730,19 +735,20 @@ Ext2WriteInode (
     return Status;
 }
 
+
 NTSTATUS
 Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
 {
-    PEXT2_VCB           Vcb;
-    PEXT2_FCB           Fcb;
-    PEXT2_CCB           Ccb;
-    PFILE_OBJECT        FileObject;
+    PEXT2_VCB           Vcb = NULL;
+    PEXT2_FCB           Fcb = NULL;
+    PEXT2_CCB           Ccb = NULL;
+    PFILE_OBJECT        FileObject = NULL;
 
-    PDEVICE_OBJECT      DeviceObject;
+    PDEVICE_OBJECT      DeviceObject = NULL;
 
-    PIRP                Irp;
-    PIO_STACK_LOCATION  IoStackLocation;
-    PUCHAR              Buffer;
+    PIRP                Irp = NULL;
+    PIO_STACK_LOCATION  IoStackLocation = NULL;
+    PUCHAR              Buffer = NULL;
 
     LARGE_INTEGER       ByteOffset;
     ULONG               ReturnedLength = 0;
@@ -803,7 +809,7 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
         DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n",
                        &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));
 
-        if (IsSpecialFile(Fcb)) {
+        if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
             Status = STATUS_INVALID_DEVICE_REQUEST;
             _SEH2_LEAVE;
         }
@@ -820,8 +826,16 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
             _SEH2_LEAVE;
         }
 
-        if (Nocache && ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
-                         (Length & (SECTOR_SIZE - 1))) ) {
+        if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
+            ByteOffset.HighPart == -1) {
+            ByteOffset = FileObject->CurrentByteOffset;
+        } else if (IsWritingToEof(ByteOffset)) {
+            ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
+        }
+
+        if (Nocache && !PagingIo &&
+            ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
+               (Length & (SECTOR_SIZE - 1))) ) {
             Status = STATUS_INVALID_PARAMETER;
             _SEH2_LEAVE;
         }
@@ -864,10 +878,6 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
             }
         }
 
-        if (IsWritingToEof(ByteOffset)) {
-            ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
-        }
-
         if (IsDirectory(Fcb) && !PagingIo) {
             Status = STATUS_INVALID_DEVICE_REQUEST;
             _SEH2_LEAVE;
@@ -904,18 +914,24 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
             }
             PagingIoResourceAcquired = TRUE;
 
-            if ( (ByteOffset.QuadPart + Length) > Fcb->Header.AllocationSize.QuadPart) {
+            if ( (ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) {
 
-                if ( ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
+                if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
 
-                    Status = STATUS_END_OF_FILE;
+                    Status = STATUS_SUCCESS;
                     Irp->IoStatus.Information = 0;
                     _SEH2_LEAVE;
 
                 } else {
 
-                    Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
+                    ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
+                    if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart)
+                        Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
                 }
+
+            } else {
+
+                ReturnedLength = Length;
             }
 
         } else {
@@ -1049,9 +1065,9 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
                               &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart,
                               Fcb->Header.AllocationSize.QuadPart));
             }
-        }
 
-        ReturnedLength = Length;
+            ReturnedLength = Length;
+        }
 
         if (!Nocache) {
 
@@ -1138,19 +1154,17 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
         } else {
 
             if (!PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
-                if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {
-                    if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {
-
-                        /* let this irp wait, since it has to be synchronous */
-                        SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-                        rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
-                                          &Fcb->Header.ValidDataLength,
-                                          &ByteOffset);
-                        if (!rc) {
-                            Status = STATUS_PENDING;
-                            DbgBreak();
-                            _SEH2_LEAVE;
-                        }
+                if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {
+
+                    /* let this irp wait, since it has to be synchronous */
+                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+                    rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
+                                      &Fcb->Header.ValidDataLength,
+                                      &ByteOffset);
+                    if (!rc) {
+                        Status = STATUS_PENDING;
+                        DbgBreak();
+                        _SEH2_LEAVE;
                     }
                 }
             }
@@ -1180,20 +1194,22 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
 
             Irp = IrpContext->Irp;
 
-            if (NT_SUCCESS(Status) && !PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
+            if (NT_SUCCESS(Status) && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
 
                 if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {
 
                     FileSizesChanged = TRUE;
 
                     if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) {
+                        if (!PagingIo)
+                            Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + Length;
                         Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
                     } else {
                         if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length)
                             Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length;
                     }
 
-                    if (CcIsFileCached(FileObject)) {
+                    if (!PagingIo && CcIsFileCached(FileObject)) {
                         CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                     }
 
@@ -1215,7 +1231,7 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
 
         /*
          *  in case we got excpetions, we need revert MajorFunction
-         *  back to IRP_MJ_WRITE. The reason we do this, if to tell
+         *  back to IRP_MJ_WRITE. The reason we do this, is to tell
          *  Ext2ExpandFile to allocate unwritten extent or don't add
          *  new blocks for indirect files.
          */