[EXT2] Upgrade to 0.69
authorPierre Schweitzer <pierre@reactos.org>
Sun, 12 Nov 2017 09:47:29 +0000 (10:47 +0100)
committerPierre Schweitzer <pierre@reactos.org>
Sun, 12 Nov 2017 09:48:17 +0000 (10:48 +0100)
CORE-13980

24 files changed:
drivers/filesystems/ext2/CMakeLists.txt
drivers/filesystems/ext2/inc/ext2fs.h
drivers/filesystems/ext2/inc/linux/errno.h
drivers/filesystems/ext2/inc/linux/ext4_xattr.h [new file with mode: 0644]
drivers/filesystems/ext2/inc/linux/fs.h
drivers/filesystems/ext2/inc/linux/module.h
drivers/filesystems/ext2/src/create.c
drivers/filesystems/ext2/src/dirctl.c
drivers/filesystems/ext2/src/dispatch.c
drivers/filesystems/ext2/src/ea.c [new file with mode: 0644]
drivers/filesystems/ext2/src/ext3/generic.c
drivers/filesystems/ext2/src/ext3/recover.c
drivers/filesystems/ext2/src/ext4/ext4_extents.c
drivers/filesystems/ext2/src/ext4/ext4_xattr.c [new file with mode: 0644]
drivers/filesystems/ext2/src/fastio.c
drivers/filesystems/ext2/src/fileinfo.c
drivers/filesystems/ext2/src/flush.c
drivers/filesystems/ext2/src/fsctl.c
drivers/filesystems/ext2/src/init.c
drivers/filesystems/ext2/src/linux.c
drivers/filesystems/ext2/src/memory.c
drivers/filesystems/ext2/src/volinfo.c
drivers/filesystems/ext2/src/write.c
media/doc/README.FSD

index 4291b27..abc1c24 100644 (file)
@@ -11,6 +11,7 @@ list(APPEND SOURCE
     src/ext4/ext4_bh.c
     src/ext4/ext4_extents.c
     src/ext4/ext4_jbd2.c
+    src/ext4/ext4_xattr.c
     src/ext4/extents.c
     src/jbd/recovery.c
     src/jbd/replay.c
@@ -66,6 +67,7 @@ list(APPEND SOURCE
     src/devctl.c
     src/dirctl.c
     src/dispatch.c
+    src/ea.c
     src/except.c
     src/fastio.c
     src/fileinfo.c
index 7792ed1..525a1d1 100644 (file)
@@ -47,7 +47,7 @@
 
 /* STRUCTS & CONSTS******************************************************/
 
-#define EXT2FSD_VERSION                 "0.68"
+#define EXT2FSD_VERSION                 "0.69"
 
 
 /* WDK DEFINITIONS ******************************************************/
@@ -720,7 +720,7 @@ typedef struct _EXT2_VCB {
     // Sector size in bits
     ULONG                       SectorBits;
 
-    // Aligned size (Page or Block)
+    // Minimal i/o size: min(PageSize, BlockSize)
     ULONGLONG                   IoUnitSize;
 
     // Bits of aligned size
@@ -783,6 +783,7 @@ typedef struct _EXT2_VCB {
 #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_GD_LOADED           0x00000100  /* group desc loaded */
 
 #define VCB_BEING_DROPPED       0x00002000
 #define VCB_FORCE_WRITING       0x00004000
@@ -929,6 +930,8 @@ struct _EXT2_MCB {
     // List Link to Vcb->McbList
     LIST_ENTRY                      Link;
 
+       
+
     struct inode                    Inode;
     struct dentry                  *de;
 };
@@ -1006,6 +1009,9 @@ typedef struct _EXT2_CCB {
     /* Open handle control block */
     struct file         filp;
 
+       /* The EA index we are on */
+       ULONG           EaIndex;
+
 } EXT2_CCB, *PEXT2_CCB;
 
 //
@@ -1116,6 +1122,10 @@ typedef struct _EXT2_EXTENT {
 #define FSCTL_GET_RETRIEVAL_POINTER_BASE    CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 141, METHOD_BUFFERED, FILE_ANY_ACCESS) // RETRIEVAL_POINTER_BASE
 #endif
 
+#ifndef FILE_SUPPORTS_EXTENDED_ATTRIBUTES
+#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES   0x00800000
+#endif
+
 //
 //  The following macro is used to determine if an FSD thread can block
 //  for I/O or wait for a resource.  It returns TRUE if the thread can
@@ -1605,6 +1615,26 @@ Ext2BuildRequest (
     IN PIRP             Irp
 );
 
+//
+// ea.c
+//
+
+NTSTATUS
+Ext2QueryEa(
+       IN PEXT2_IRP_CONTEXT    IrpContext
+);
+
+BOOLEAN
+Ext2IsEaNameValid(
+       IN OEM_STRING Name
+);
+
+NTSTATUS
+Ext2SetEa(
+       IN PEXT2_IRP_CONTEXT    IrpContext
+);
+
+
 //
 // Except.c
 //
@@ -1765,15 +1795,24 @@ Ext2RefreshSuper(
     IN PEXT2_VCB            Vcb
 );
 
+BOOLEAN
+Ext2LoadGroupBH(IN PEXT2_VCB Vcb);
+
 BOOLEAN
 Ext2LoadGroup(IN PEXT2_VCB Vcb);
 
+VOID
+Ext2DropGroupBH(IN PEXT2_VCB Vcb);
+
 VOID
 Ext2PutGroup(IN PEXT2_VCB Vcb);
 
 VOID
 Ext2DropBH(IN PEXT2_VCB Vcb);
 
+NTSTATUS
+Ext2FlushVcb(IN PEXT2_VCB Vcb);
+
 BOOLEAN
 Ext2SaveGroup(
     IN PEXT2_IRP_CONTEXT    IrpContext,
@@ -1814,6 +1853,17 @@ Ext2SaveInode (
     IN struct inode *Inode
 );
 
+BOOLEAN
+Ext2LoadInodeXattr(IN PEXT2_VCB Vcb,
+       IN struct inode *Inode,
+       IN PEXT2_INODE InodeXattr);
+
+BOOLEAN
+Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext,
+       IN PEXT2_VCB Vcb,
+       IN struct inode *Inode,
+       IN PEXT2_INODE InodeXattr);
+
 BOOLEAN
 Ext2LoadBlock (
     IN PEXT2_VCB Vcb,
@@ -1829,6 +1879,15 @@ Ext2SaveBlock (
     IN PVOID                Buf
 );
 
+BOOLEAN
+Ext2LoadBuffer(
+    IN PEXT2_IRP_CONTEXT    IrpContext,
+    IN PEXT2_VCB            Vcb,
+    IN LONGLONG             Offset,
+    IN ULONG                Size,
+    IN PVOID                Buf
+);
+
 BOOLEAN
 Ext2ZeroBuffer(
     IN PEXT2_IRP_CONTEXT    IrpContext,
index 5173d2a..13bcbf4 100644 (file)
@@ -61,7 +61,9 @@
 
 #define        EBFONT          59      /* Bad font file format */
 #define        ENOSTR          60      /* Device not a stream */
+#endif
 #define        ENODATA         61      /* No data available */
+#ifndef __REACTOS__
 #define        ETIME           62      /* Timer expired */
 #define        ENOSR           63      /* Out of streams resources */
 #define        ENONET          64      /* Machine is not on the network */
diff --git a/drivers/filesystems/ext2/inc/linux/ext4_xattr.h b/drivers/filesystems/ext2/inc/linux/ext4_xattr.h
new file mode 100644 (file)
index 0000000..d57949c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2015 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * Copyright (c) 2015 Kaho Ng (ngkaho1234@gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file  ext4_xattr.h
+ * @brief Extended Attribute manipulation.
+ */
+
+#ifndef EXT4_XATTR_H_
+#define EXT4_XATTR_H_
+
+#include <ext2fs.h>
+#include <linux/rbtree.h>
+
+/* Extended Attribute(EA) */
+
+/* Magic value in attribute blocks */
+#define EXT4_XATTR_MAGIC               0xEA020000
+
+/* Maximum number of references to one attribute block */
+#define EXT4_XATTR_REFCOUNT_MAX                1024
+
+/* Name indexes */
+#define EXT4_XATTR_INDEX_USER                  1
+#define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS      2
+#define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT     3
+#define EXT4_XATTR_INDEX_TRUSTED               4
+#define        EXT4_XATTR_INDEX_LUSTRE                 5
+#define EXT4_XATTR_INDEX_SECURITY              6
+#define EXT4_XATTR_INDEX_SYSTEM                        7
+#define EXT4_XATTR_INDEX_RICHACL               8
+#define EXT4_XATTR_INDEX_ENCRYPTION            9
+
+#pragma pack(push, 1)
+
+struct ext4_xattr_header {
+       __le32 h_magic; /* magic number for identification */
+       __le32 h_refcount;      /* reference count */
+       __le32 h_blocks;        /* number of disk blocks used */
+       __le32 h_hash;          /* hash value of all attributes */
+       __le32 h_checksum;      /* crc32c(uuid+id+xattrblock) */
+                               /* id = inum if refcount=1, blknum otherwise */
+       __le32 h_reserved[3];   /* zero right now */
+};
+
+struct ext4_xattr_ibody_header {
+       __le32 h_magic; /* magic number for identification */
+};
+
+struct ext4_xattr_entry {
+       __u8 e_name_len;        /* length of name */
+       __u8 e_name_index;      /* attribute name index */
+       __le16 e_value_offs;    /* offset in disk block of value */
+       __le32 e_value_block;   /* disk block attribute is stored on (n/i) */
+       __le32 e_value_size;    /* size of attribute value */
+       __le32 e_hash;          /* hash value of name and value */
+};
+
+#pragma pack(pop)
+
+#define EXT4_GOOD_OLD_INODE_SIZE       EXT2_GOOD_OLD_INODE_SIZE
+
+#define EXT4_XATTR_PAD_BITS            2
+#define EXT4_XATTR_PAD         (1<<EXT4_XATTR_PAD_BITS)
+#define EXT4_XATTR_ROUND               (EXT4_XATTR_PAD-1)
+#define EXT4_XATTR_LEN(name_len) \
+       (((name_len) + EXT4_XATTR_ROUND + \
+       sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
+#define EXT4_XATTR_NEXT(entry) \
+       ((struct ext4_xattr_entry *)( \
+        (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)))
+#define EXT4_XATTR_SIZE(size) \
+       (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
+#define EXT4_XATTR_NAME(entry) \
+       ((char *)((entry) + 1))
+
+#define EXT4_XATTR_IHDR(raw_inode) \
+       ((struct ext4_xattr_ibody_header *) \
+               ((char *)raw_inode + \
+               EXT4_GOOD_OLD_INODE_SIZE + \
+               (raw_inode)->i_extra_isize))
+#define EXT4_XATTR_IFIRST(hdr) \
+       ((struct ext4_xattr_entry *)((hdr)+1))
+
+#define EXT4_XATTR_BHDR(block) \
+       ((struct ext4_xattr_header *)((block)->b_data))
+#define EXT4_XATTR_ENTRY(ptr) \
+       ((struct ext4_xattr_entry *)(ptr))
+#define EXT4_XATTR_BFIRST(block) \
+       EXT4_XATTR_ENTRY(EXT4_XATTR_BHDR(block)+1)
+#define EXT4_XATTR_IS_LAST_ENTRY(entry) \
+       (*(__le32 *)(entry) == 0)
+
+#define EXT4_ZERO_XATTR_VALUE ((void *)-1)
+
+
+struct ext4_xattr_item {
+       /* This attribute should be stored in inode body */
+       BOOL in_inode;
+       BOOL is_data;
+
+       __u8 name_index;
+       char  *name;
+       size_t name_len;
+       void  *data;
+       size_t data_size;
+
+       struct rb_node node;
+       struct list_head list_node;
+};
+
+struct ext4_xattr_ref {
+       PEXT2_IRP_CONTEXT IrpContext;
+       BOOL block_loaded;
+       struct buffer_head *block_bh;
+       PEXT2_MCB inode_ref;
+
+       PEXT2_INODE OnDiskInode;
+       BOOL IsOnDiskInodeDirty;
+
+       BOOL   dirty;
+       size_t ea_size;
+       size_t inode_size_rem;
+       size_t block_size_rem;
+       PEXT2_VCB fs;
+
+       void *iter_arg;
+       struct ext4_xattr_item *iter_from;
+
+       struct rb_root root;
+       struct list_head ordered_list;
+};
+
+#define EXT4_XATTR_ITERATE_CONT 0
+#define EXT4_XATTR_ITERATE_STOP 1
+#define EXT4_XATTR_ITERATE_PAUSE 2
+
+int ext4_fs_get_xattr_ref(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB fs, PEXT2_MCB inode_ref,
+       struct ext4_xattr_ref *ref);
+
+int ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref);
+
+int ext4_fs_set_xattr(struct ext4_xattr_ref *ref, __u8 name_index,
+                     const char *name, size_t name_len, const void *data,
+                     size_t data_size, BOOL replace);
+
+int ext4_fs_set_xattr_ordered(struct ext4_xattr_ref *ref, __u8 name_index,
+       const char *name, size_t name_len, const void *data,
+       size_t data_size);
+
+int ext4_fs_remove_xattr(struct ext4_xattr_ref *ref, __u8 name_index,
+                        const char *name, size_t name_len);
+
+int ext4_fs_get_xattr(struct ext4_xattr_ref *ref, __u8 name_index,
+                     const char *name, size_t name_len, void *buf,
+                     size_t buf_size, size_t *data_size);
+
+void ext4_fs_xattr_iterate(struct ext4_xattr_ref *ref,
+       int(*iter)(struct ext4_xattr_ref *ref,
+               struct ext4_xattr_item *item,
+               BOOL is_last));
+
+void ext4_fs_xattr_iterate_reset(struct ext4_xattr_ref *ref);
+
+const char *ext4_extract_xattr_name(const char *full_name, size_t full_name_len,
+                             __u8 *name_index, size_t *name_len,
+                             BOOL *found);
+
+const char *ext4_get_xattr_name_prefix(__u8 name_index,
+                                      size_t *ret_prefix_len);
+
+void ext4_xattr_purge_items(struct ext4_xattr_ref *xattr_ref);
+
+#endif
+/**
+ * @}
+ */
index 52a8b3d..5da58f9 100644 (file)
@@ -75,25 +75,6 @@ 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 */
index 141e8fd..65607b6 100644 (file)
@@ -864,6 +864,8 @@ struct buffer_head *extents_bread(struct super_block *sb, sector_t block);
 struct buffer_head *extents_bwrite(struct super_block *sb, sector_t block);
 void extents_mark_buffer_dirty(struct buffer_head *bh);
 void extents_brelse(struct buffer_head *bh);
+void extents_bforget(struct buffer_head *bh);
+void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh);
 
 extern int buffer_heads_over_limit;
 
index 251343f..01c5cfb 100644 (file)
@@ -10,6 +10,7 @@
 /* INCLUDES *****************************************************************/
 
 #include "ext2fs.h"
+#include <linux/ext4_xattr.h>
 
 /* GLOBALS *****************************************************************/
 
@@ -350,8 +351,9 @@ Ext2LookupFile (
         }
 
         /* is a directory expected ? */
-        if (FullName->Buffer[End - 1] == L'\\') {
+        while (FullName->Buffer[End - 1] == L'\\') {
             bDirectory = TRUE;
+            End -= 1;
         }
 
         /* loop with every sub name */
@@ -674,6 +676,155 @@ errorout:
     return Ext2WinntError(rc);
 }
 
+//
+// Any call to this routine must have Fcb's MainResource and FcbLock acquired.
+//
+
+NTSTATUS
+Ext2OverwriteEa(
+       PEXT2_IRP_CONTEXT    IrpContext,
+       PEXT2_VCB Vcb,
+       PEXT2_FCB Fcb,
+       PIO_STATUS_BLOCK Iosb
+)
+{
+    PEXT2_MCB           Mcb = NULL;
+    PIRP                                 Irp;
+    PIO_STACK_LOCATION  IrpSp;
+
+    struct ext4_xattr_ref xattr_ref;
+    BOOLEAN             XattrRefAcquired = FALSE;
+    NTSTATUS            Status = STATUS_UNSUCCESSFUL;
+
+    PFILE_FULL_EA_INFORMATION FullEa;
+    PCHAR EaBuffer;
+    ULONG EaBufferLength;
+
+    _SEH2_TRY {
+
+        Irp = IrpContext->Irp;
+        IrpSp = IoGetCurrentIrpStackLocation(Irp);
+        Mcb = Fcb->Mcb;
+
+        EaBuffer = Irp->AssociatedIrp.SystemBuffer;
+        EaBufferLength = IrpSp->Parameters.Create.EaLength;
+
+        if (!Mcb)
+            _SEH2_LEAVE;
+
+        //
+        // Return peacefully if there is no EaBuffer provided.
+        //
+        if (!EaBuffer) {
+            Status = STATUS_SUCCESS;
+            _SEH2_LEAVE;
+        }
+
+               //
+               // If the caller specifies an EaBuffer, but has no knowledge about Ea,
+               // we reject the request.
+               //
+               if (EaBuffer != NULL &&
+                       FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_EA_KNOWLEDGE)) {
+                       Status = STATUS_ACCESS_DENIED;
+                       _SEH2_LEAVE;
+               }
+
+        //
+        // Check Ea Buffer validity.
+        //
+        Status = IoCheckEaBufferValidity((PFILE_FULL_EA_INFORMATION)EaBuffer,
+                                          EaBufferLength, (PULONG)&Iosb->Information);
+        if (!NT_SUCCESS(Status))
+            _SEH2_LEAVE;
+
+        Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
+        if (!NT_SUCCESS(Status)) {
+            DbgPrint("ext4_fs_get_xattr_ref() failed!\n");
+            _SEH2_LEAVE;
+        }
+
+        XattrRefAcquired = TRUE;
+
+        //
+        // Remove all existing EA entries.
+        //
+        ext4_xattr_purge_items(&xattr_ref);
+        xattr_ref.dirty = TRUE;
+        Status = STATUS_SUCCESS;
+
+        // Iterate the whole EA buffer to do inspection
+        for (FullEa = (PFILE_FULL_EA_INFORMATION)EaBuffer;
+            FullEa < (PFILE_FULL_EA_INFORMATION)&EaBuffer[EaBufferLength];
+            FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ?
+                &EaBuffer[EaBufferLength] :
+                (PCHAR)FullEa + FullEa->NextEntryOffset)) {
+
+            OEM_STRING EaName;
+
+            EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
+            EaName.Buffer = &FullEa->EaName[0];
+
+            // Check if EA's name is valid
+            if (!Ext2IsEaNameValid(EaName)) {
+                Status = STATUS_INVALID_EA_NAME;
+                _SEH2_LEAVE;
+            }
+        }
+
+        // Now add EA entries to the inode
+        for (FullEa = (PFILE_FULL_EA_INFORMATION)EaBuffer;
+            FullEa < (PFILE_FULL_EA_INFORMATION)&EaBuffer[EaBufferLength];
+            FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ?
+                &EaBuffer[EaBufferLength] :
+                (PCHAR)FullEa + FullEa->NextEntryOffset)) {
+
+            int ret;
+            OEM_STRING EaName;
+
+            EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
+            EaName.Buffer = &FullEa->EaName[0];
+
+            Status = Ext2WinntError(ret =
+                ext4_fs_set_xattr(&xattr_ref,
+                    EXT4_XATTR_INDEX_USER,
+                    EaName.Buffer,
+                    EaName.Length,
+                    &FullEa->EaName[0] + FullEa->EaNameLength + 1,
+                    FullEa->EaValueLength,
+                    TRUE));
+            if (!NT_SUCCESS(Status) && ret != -ENODATA)
+                _SEH2_LEAVE;
+
+            if (ret == -ENODATA) {
+                Status = Ext2WinntError(
+                    ext4_fs_set_xattr(&xattr_ref,
+                        EXT4_XATTR_INDEX_USER,
+                        EaName.Buffer,
+                        EaName.Length,
+                        &FullEa->EaName[0] + FullEa->EaNameLength + 1,
+                        FullEa->EaValueLength,
+                        FALSE));
+                if (!NT_SUCCESS(Status))
+                    _SEH2_LEAVE;
+
+            }
+        }
+    }
+    _SEH2_FINALLY {
+
+        if (XattrRefAcquired) {
+            if (!NT_SUCCESS(Status)) {
+                xattr_ref.dirty = FALSE;
+                ext4_fs_put_xattr_ref(&xattr_ref);
+                       } else {
+                               Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref));
+                       }
+        }
+    } _SEH2_END;
+    return Status;
+}
+
 NTSTATUS
 Ext2CreateFile(
     PEXT2_IRP_CONTEXT IrpContext,
@@ -876,13 +1027,17 @@ McbExisting:
             PathName = FileName;
             Mcb = NULL;
 
-            if (PathName.Buffer[PathName.Length/2 - 1] == L'\\') {
-                if (DirectoryFile) {
-                    PathName.Length -=2;
-                    PathName.Buffer[PathName.Length/2] = 0;
-                } else {
-                    DirectoryFile = TRUE;
-                }
+            /* here we've found the target file, but it's not matched. */
+            if (STATUS_OBJECT_NAME_NOT_FOUND != Status &&
+                STATUS_NO_SUCH_FILE != Status) {
+                _SEH2_LEAVE;
+            }
+
+            while (PathName.Length > 0 &&
+                   PathName.Buffer[PathName.Length/2 - 1] == L'\\') {
+                DirectoryFile = TRUE;
+                PathName.Length -= 2;
+                PathName.Buffer[PathName.Length / 2] = 0;
             }
 
             if (!ParentMcb) {
@@ -922,7 +1077,8 @@ Dissecting:
 
                 /* quit name resolving loop */
                 if (!NT_SUCCESS(Status)) {
-                    if (Status == STATUS_NO_SUCH_FILE && RemainName.Length != 0) {
+                    if (Status == STATUS_NO_SUCH_FILE ||
+                        Status == STATUS_OBJECT_NAME_NOT_FOUND) {
                         Status = STATUS_OBJECT_PATH_NOT_FOUND;
                     }
                     _SEH2_LEAVE;
@@ -1296,6 +1452,12 @@ Openit:
                 //  This file is just created.
                 //
 
+                               Status = Ext2OverwriteEa(IrpContext, Vcb, Fcb, &Irp->IoStatus);
+                               if (!NT_SUCCESS(Status)) {
+                                       Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
+                                       _SEH2_LEAVE;
+                               }
+
                 if (DirectoryFile) {
 
                     Status = Ext2AddDotEntries(IrpContext, &ParentMcb->Inode, &Mcb->Inode);
@@ -1758,7 +1920,9 @@ Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
         SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
         Vcb->LockFile = IrpSp->FileObject;
     } else {
-        if (FlagOn(DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA) ) {
+
+        if (FlagOn(IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING) &&
+            FlagOn(DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA) ) {
             if (!IsVcbReadOnly(Vcb)) {
                 Ext2FlushFiles(IrpContext, Vcb, FALSE);
                 Ext2FlushVolume(IrpContext, Vcb, FALSE);
@@ -1888,6 +2052,7 @@ Ext2CreateInode(
     ULONG       iNo;
     struct inode Inode = { 0 };
     struct dentry *Dentry = NULL;
+       struct ext3_super_block *es = EXT3_SB(&Vcb->sb)->s_es;
 
     LARGE_INTEGER   SysTime;
 
@@ -1927,6 +2092,8 @@ Ext2CreateInode(
     } else {
         DbgBreak();
     }
+       if (le16_to_cpu(es->s_want_extra_isize))
+               Inode.i_extra_isize = le16_to_cpu(es->s_want_extra_isize);
 
     /* Force using extent */
     if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
@@ -2022,5 +2189,6 @@ Ext2SupersedeOrOverWriteFile(
         Fcb->Inode->i_mtime = Ext2LinuxTime(CurrentTime);
     Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);
 
-    return STATUS_SUCCESS;
+    // See if we need to overwrite EA of the file
+    return Ext2OverwriteEa(IrpContext, Vcb, Fcb, &IrpContext->Irp->IoStatus);
 }
index b76385d..668b9c2 100644 (file)
@@ -1085,6 +1085,12 @@ Ext2NotifyChangeDirectory (
         ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
                (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
 
+        /* do nothing if target fie was deleted */
+        if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
+            Status = STATUS_FILE_DELETED;
+            _SEH2_LEAVE;
+        }
+
         if (!IsDirectory(Fcb)) {
             DbgBreak();
             Status = STATUS_INVALID_PARAMETER;
index 35e4fe2..3e13af6 100644 (file)
@@ -267,6 +267,12 @@ Ext2DispatchRequest (IN PEXT2_IRP_CONTEXT IrpContext)
     case IRP_MJ_SHUTDOWN:
         return Ext2ShutDown(IrpContext);
 
+       case IRP_MJ_QUERY_EA:
+               return Ext2QueryEa(IrpContext);
+
+       case IRP_MJ_SET_EA:
+               return Ext2SetEa(IrpContext);
+
 #if (_WIN32_WINNT >= 0x0500)
     case IRP_MJ_PNP:
         return Ext2Pnp(IrpContext);
diff --git a/drivers/filesystems/ext2/src/ea.c b/drivers/filesystems/ext2/src/ea.c
new file mode 100644 (file)
index 0000000..2f7d4ce
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+* COPYRIGHT:        See COPYRIGHT.TXT
+* PROJECT:          Ext2 File System Driver for Windows >= NT
+* FILE:             ea.c
+* PROGRAMMER:       Matt Wu <mattwu@163.com>  Kaho Ng <ngkaho1234@gmail.com>
+* HOMEPAGE:         http://www.ext2fsd.com
+* UPDATE HISTORY:
+*/
+
+/* INCLUDES *****************************************************************/
+
+#include "ext2fs.h"
+#include <linux/ext4_xattr.h>
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, Ext2QueryEa)
+#pragma alloc_text(PAGE, Ext2SetEa)
+#pragma alloc_text(PAGE, Ext2IsEaNameValid)
+#endif
+
+// Ea iterator
+struct EaIterator {
+       // Return only an entry
+       BOOLEAN ReturnSingleEntry;
+
+       // Is the buffer overflowing?
+       BOOL OverFlow;
+
+       // FILE_FULL_EA_INFORMATION output buffer
+       PFILE_FULL_EA_INFORMATION FullEa;
+       PFILE_FULL_EA_INFORMATION LastFullEa;
+
+       // UserBuffer's size
+       ULONG UserBufferLength;
+
+       // Remaining UserBuffer's size
+       ULONG RemainingUserBufferLength;
+
+       // Start scanning from this EA
+       ULONG EaIndex;
+
+       // Next EA index returned by Ext2IterateAllEa
+       ULONG EaIndexCounter;
+};
+
+static int Ext2IterateAllEa(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item, BOOL is_last)
+{
+       struct EaIterator *pEaIterator = xattr_ref->iter_arg;
+       ULONG EaEntrySize = 4 + 1 + 1 + 2 + item->name_len + 1 + item->data_size;
+       ASSERT(pEaIterator);
+       if (!is_last && !pEaIterator->ReturnSingleEntry)
+               EaEntrySize = ALIGN_UP(EaEntrySize, ULONG);
+
+       // Start iteration from index specified
+       if (pEaIterator->EaIndexCounter < pEaIterator->EaIndex) {
+               pEaIterator->EaIndexCounter++;
+               return EXT4_XATTR_ITERATE_CONT;
+       }
+       pEaIterator->EaIndexCounter++;
+
+       if (EaEntrySize > pEaIterator->RemainingUserBufferLength) {
+               pEaIterator->OverFlow = TRUE;
+               return EXT4_XATTR_ITERATE_STOP;
+       }
+       pEaIterator->FullEa->NextEntryOffset = 0;
+       pEaIterator->FullEa->Flags = 0;
+       pEaIterator->FullEa->EaNameLength = (UCHAR)item->name_len;
+       pEaIterator->FullEa->EaValueLength = (USHORT)item->data_size;
+       RtlCopyMemory(&pEaIterator->FullEa->EaName[0],
+               item->name,
+               item->name_len);
+       RtlCopyMemory(&pEaIterator->FullEa->EaName[0] + item->name_len + 1,
+               item->data,
+               item->data_size);
+
+       // Link FullEa and LastFullEa together
+       if (pEaIterator->LastFullEa) {
+               pEaIterator->LastFullEa->NextEntryOffset = (ULONG)
+                       ((PCHAR)pEaIterator->FullEa - (PCHAR)pEaIterator->LastFullEa);
+       }
+
+       pEaIterator->LastFullEa = pEaIterator->FullEa;
+       pEaIterator->FullEa = (PFILE_FULL_EA_INFORMATION)
+                       ((PCHAR)pEaIterator->FullEa + EaEntrySize);
+       pEaIterator->RemainingUserBufferLength -= EaEntrySize;
+
+       if (pEaIterator->ReturnSingleEntry)
+               return EXT4_XATTR_ITERATE_STOP;
+
+       return EXT4_XATTR_ITERATE_CONT;
+}
+
+NTSTATUS
+Ext2QueryEa (
+       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;
+
+       PUCHAR  UserEaList;
+       ULONG   UserEaListLength;
+       ULONG   UserEaIndex;
+
+       BOOLEAN RestartScan;
+       BOOLEAN ReturnSingleEntry;
+       BOOLEAN IndexSpecified;
+
+       BOOLEAN             MainResourceAcquired = FALSE;
+       BOOLEAN             XattrRefAcquired = FALSE;
+
+       NTSTATUS            Status = STATUS_UNSUCCESSFUL;
+
+       struct ext4_xattr_ref xattr_ref;
+       PCHAR UserBuffer;
+
+       ULONG UserBufferLength = 0;
+       ULONG RemainingUserBufferLength = 0;
+
+       PFILE_FULL_EA_INFORMATION FullEa, LastFullEa = 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;
+               Fcb = IrpContext->Fcb;
+               Mcb = Fcb->Mcb;
+               Irp = IrpContext->Irp;
+               IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+               Irp->IoStatus.Information = 0;
+
+               //
+               // Receive input parameter from caller
+               //
+               UserBuffer = Ext2GetUserBuffer(Irp);
+               if (!UserBuffer) {
+                       Status = STATUS_INSUFFICIENT_RESOURCES;
+                       _SEH2_LEAVE;
+               }
+               UserBufferLength = IrpSp->Parameters.QueryEa.Length;
+               RemainingUserBufferLength = UserBufferLength;
+               UserEaList = IrpSp->Parameters.QueryEa.EaList;
+               UserEaListLength = IrpSp->Parameters.QueryEa.EaListLength;
+               UserEaIndex = IrpSp->Parameters.QueryEa.EaIndex;
+               RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
+               ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
+               IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
+
+               if (!Mcb)
+                       _SEH2_LEAVE;
+
+               //
+               // We do not allow multiple instance gaining EA access to the same file
+               //
+               if (!ExAcquireResourceExclusiveLite(
+                       &Fcb->MainResource,
+                       IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
+                       Status = STATUS_PENDING;
+                       _SEH2_LEAVE;
+               }
+               MainResourceAcquired = TRUE;
+
+               Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
+               if (!NT_SUCCESS(Status)) {
+                       DbgPrint("ext4_fs_get_xattr_ref() failed!\n");
+                       _SEH2_LEAVE;
+               }
+
+               FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
+
+               XattrRefAcquired = TRUE;
+
+               if (RemainingUserBufferLength)
+                       RtlZeroMemory(FullEa, RemainingUserBufferLength);
+
+               if (UserEaList != NULL) {
+                       int i = 0;
+                       PFILE_GET_EA_INFORMATION GetEa;
+                       for (GetEa = (PFILE_GET_EA_INFORMATION)&UserEaList[0];
+                                       GetEa < (PFILE_GET_EA_INFORMATION)((PUCHAR)UserEaList
+                                       + UserEaListLength);
+                               GetEa = (GetEa->NextEntryOffset == 0
+                                       ? (PFILE_GET_EA_INFORMATION)MAXUINT_PTR
+                                       : (PFILE_GET_EA_INFORMATION)((PUCHAR)GetEa
+                                               + GetEa->NextEntryOffset))) {
+
+                               size_t ItemSize;
+                               OEM_STRING Str;
+                               ULONG EaEntrySize;
+                               BOOL is_last = !GetEa->NextEntryOffset;
+
+                               Str.MaximumLength = Str.Length = GetEa->EaNameLength;
+                               Str.Buffer = &GetEa->EaName[0];
+
+                               //
+                               // At the moment we only need to know whether the item exists
+                               // and its size.
+                               //
+                               Status = Ext2WinntError(ext4_fs_get_xattr(&xattr_ref,
+                                       EXT4_XATTR_INDEX_USER,
+                                       Str.Buffer,
+                                       Str.Length,
+                                       NULL,
+                                       0,
+                                       &ItemSize));
+                               if (!NT_SUCCESS(Status))
+                                       continue;
+
+                               //
+                               //  We were not able to locate the name therefore we must
+                               //  dummy up a entry for the query.  The needed Ea size is
+                               //  the size of the name + 4 (next entry offset) + 1 (flags)
+                               //  + 1 (name length) + 2 (value length) + the name length +
+                               //  1 (null byte) + Data Size.
+                               //
+                               EaEntrySize = 4 + 1 + 1 + 2 + GetEa->EaNameLength + 1 + ItemSize;
+                               if (!is_last)
+                                       EaEntrySize = ALIGN_UP(EaEntrySize, ULONG);
+
+                               if (EaEntrySize > RemainingUserBufferLength) {
+
+                                       Status = i ? STATUS_BUFFER_OVERFLOW : STATUS_BUFFER_TOO_SMALL;
+                                       _SEH2_LEAVE;
+                               }
+                               FullEa->NextEntryOffset = 0;
+                               FullEa->Flags = 0;
+                               FullEa->EaNameLength = GetEa->EaNameLength;
+                               FullEa->EaValueLength = (USHORT)ItemSize;
+                               RtlCopyMemory(&FullEa->EaName[0],
+                                       &GetEa->EaName[0],
+                                       GetEa->EaNameLength);
+
+                               //
+                               // This query must succeed, or is guarenteed to succeed
+                               // since we are only looking up
+                               // an EA entry in a in-memory tree structure.
+                               // Otherwise that means someone might be operating on
+                               // the xattr_ref without acquiring Inode lock.
+                               //
+                               ASSERT(NT_SUCCESS(Ext2WinntError(
+                                       ext4_fs_get_xattr(&xattr_ref,
+                                               EXT4_XATTR_INDEX_USER,
+                                               Str.Buffer,
+                                               Str.Length,
+                                               &FullEa->EaName[0] + FullEa->EaNameLength + 1,
+                                               ItemSize,
+                                               &ItemSize
+                               ))));
+                               FullEa->EaValueLength = (USHORT)ItemSize;
+
+                               // Link FullEa and LastFullEa together
+                               if (LastFullEa)
+                                       LastFullEa->NextEntryOffset = (ULONG)((PCHAR)FullEa - 
+                                                          (PCHAR)LastFullEa);
+
+                               LastFullEa = FullEa;
+                               FullEa = (PFILE_FULL_EA_INFORMATION)
+                                       ((PCHAR)FullEa + EaEntrySize);
+                               RemainingUserBufferLength -= EaEntrySize;
+                               i++;
+                       }
+               } else if (IndexSpecified) {
+                       struct EaIterator EaIterator;
+                       //
+                       //  The user supplied an index into the Ea list.
+                       //
+                       if (RemainingUserBufferLength)
+                               RtlZeroMemory(FullEa, RemainingUserBufferLength);
+
+                       EaIterator.OverFlow = FALSE;
+                       EaIterator.RemainingUserBufferLength = UserBufferLength;
+                       // In this case, return only an entry.
+                       EaIterator.ReturnSingleEntry = TRUE;
+                       EaIterator.FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
+                       EaIterator.LastFullEa = NULL;
+                       EaIterator.UserBufferLength = UserBufferLength;
+                       EaIterator.EaIndex = UserEaIndex;
+                       EaIterator.EaIndexCounter = 1;
+
+                       xattr_ref.iter_arg = &EaIterator;
+                       ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa);
+
+                       RemainingUserBufferLength = EaIterator.RemainingUserBufferLength;
+
+                       Status = STATUS_SUCCESS;
+
+                       // It seems that the item isn't found
+                       if (RemainingUserBufferLength == UserBufferLength)
+                               Status = STATUS_OBJECTID_NOT_FOUND;
+
+                       if (EaIterator.OverFlow) {
+                               if (RemainingUserBufferLength == UserBufferLength)
+                                       Status = STATUS_BUFFER_TOO_SMALL;
+                               else
+                                       Status = STATUS_BUFFER_OVERFLOW;
+                       }
+
+               } else {
+                       struct EaIterator EaIterator;
+                       //
+                       //  Else perform a simple scan, taking into account the restart
+                       //  flag and the position of the next Ea stored in the Ccb.
+                       //
+                       if (RestartScan)
+                               Ccb->EaIndex = 1;
+
+                       if (RemainingUserBufferLength)
+                               RtlZeroMemory(FullEa, RemainingUserBufferLength);
+
+                       EaIterator.OverFlow = FALSE;
+                       EaIterator.RemainingUserBufferLength = UserBufferLength;
+                       EaIterator.ReturnSingleEntry = ReturnSingleEntry;
+                       EaIterator.FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
+                       EaIterator.LastFullEa = NULL;
+                       EaIterator.UserBufferLength = UserBufferLength;
+                       EaIterator.EaIndex = Ccb->EaIndex;
+                       EaIterator.EaIndexCounter = 1;
+
+                       xattr_ref.iter_arg = &EaIterator;
+                       ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa);
+
+                       RemainingUserBufferLength = EaIterator.RemainingUserBufferLength;
+
+                       if (Ccb->EaIndex < EaIterator.EaIndexCounter)
+                               Ccb->EaIndex = EaIterator.EaIndexCounter;
+
+                       Status = STATUS_SUCCESS;
+
+                       if (EaIterator.OverFlow) {
+                               if (RemainingUserBufferLength == UserBufferLength)
+                                       Status = STATUS_BUFFER_TOO_SMALL;
+                               else
+                                       Status = STATUS_BUFFER_OVERFLOW;
+                       }
+
+               }
+       }
+       _SEH2_FINALLY {
+
+               if (XattrRefAcquired) {
+                       if (!NT_SUCCESS(Status)) {
+                               xattr_ref.dirty = FALSE;
+                               ext4_fs_put_xattr_ref(&xattr_ref);
+                       }
+                       else
+                               Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref));
+               }
+
+               if (MainResourceAcquired) {
+                       ExReleaseResourceLite(&Fcb->MainResource);
+               }
+
+               if (NT_SUCCESS(Status)) {
+                       Ext2NotifyReportChange(
+                               IrpContext,
+                               Vcb,
+                               Mcb,
+                               FILE_NOTIFY_CHANGE_EA,
+                               FILE_ACTION_MODIFIED);
+                       Irp->IoStatus.Information = UserBufferLength - RemainingUserBufferLength;
+               }
+
+               if (!_SEH2_AbnormalTermination()) {
+                       if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+                               Status = Ext2QueueRequest(IrpContext);
+                       }
+                       else {
+                               Ext2CompleteIrpContext(IrpContext, Status);
+                       }
+               }
+       } _SEH2_END;
+
+       return Status;
+}
+
+BOOLEAN
+Ext2IsEaNameValid(
+       IN OEM_STRING Name
+)
+{
+       ULONG Index;
+       UCHAR Char;
+
+       //
+       //  Empty names are not valid
+       //
+
+       if (Name.Length == 0)
+               return FALSE;
+
+       //
+       // Do not allow EA name longer than 255 bytes
+       //
+       if (Name.Length > 255)
+               return FALSE;
+
+       for (Index = 0; Index < (ULONG)Name.Length; Index += 1) {
+
+               Char = Name.Buffer[Index];
+
+               //
+               //  Skip over and Dbcs chacters
+               //
+               if (FsRtlIsLeadDbcsCharacter(Char)) {
+
+                       ASSERT(Index != (ULONG)(Name.Length - 1));
+                       Index += 1;
+                       continue;
+               }
+
+               //
+               //  Make sure this character is legal, and if a wild card, that
+               //  wild cards are permissible.
+               //
+               if (!FsRtlIsAnsiCharacterLegalFat(Char, FALSE))
+                       return FALSE;
+
+       }
+
+       return TRUE;
+}
+
+NTSTATUS
+Ext2SetEa (
+       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;
+
+       BOOLEAN             MainResourceAcquired = FALSE;
+       BOOLEAN             FcbLockAcquired = FALSE;
+       BOOLEAN             XattrRefAcquired = FALSE;
+
+       NTSTATUS            Status = STATUS_UNSUCCESSFUL;
+
+       struct ext4_xattr_ref xattr_ref;
+       PCHAR UserBuffer;
+       ULONG UserBufferLength;
+
+       PFILE_FULL_EA_INFORMATION FullEa;
+
+       _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);
+
+               Irp->IoStatus.Information = 0;
+
+               //
+               // Receive input parameter from caller
+               //
+               UserBufferLength = IrpSp->Parameters.SetEa.Length;
+               UserBuffer = Irp->UserBuffer;
+
+               // Check if the EA buffer provided is valid
+               Status = IoCheckEaBufferValidity((PFILE_FULL_EA_INFORMATION)UserBuffer,
+                       UserBufferLength,
+                       (PULONG)&Irp->IoStatus.Information);
+               if (!NT_SUCCESS(Status))
+                       _SEH2_LEAVE;
+
+               ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+               FcbLockAcquired = TRUE;
+
+               if (!Mcb)
+                       _SEH2_LEAVE;
+
+               //
+               // We do not allow multiple instance gaining EA access to the same file
+               //
+               if (!ExAcquireResourceExclusiveLite(
+                       &Fcb->MainResource,
+                       IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
+                       Status = STATUS_PENDING;
+                       _SEH2_LEAVE;
+               }
+               MainResourceAcquired = TRUE;
+
+               Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
+               if (!NT_SUCCESS(Status)) {
+                       DbgPrint("ext4_fs_get_xattr_ref() failed!\n");
+                       _SEH2_LEAVE;
+               }
+
+               XattrRefAcquired = TRUE;
+
+               //
+               // Remove all existing EA entries.
+               //
+               ext4_xattr_purge_items(&xattr_ref);
+               xattr_ref.dirty = TRUE;
+               Status = STATUS_SUCCESS;
+
+               // Iterate the whole EA buffer to do inspection
+               for (FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
+                       FullEa < (PFILE_FULL_EA_INFORMATION)&UserBuffer[UserBufferLength];
+                       FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ?
+                               &UserBuffer[UserBufferLength] :
+                               (PCHAR)FullEa + FullEa->NextEntryOffset)) {
+
+                       OEM_STRING EaName;
+
+                       EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
+                       EaName.Buffer = &FullEa->EaName[0];
+
+                       // Check if EA's name is valid
+                       if (!Ext2IsEaNameValid(EaName)) {
+                               Irp->IoStatus.Information = (PCHAR)FullEa - UserBuffer;
+                               Status = STATUS_INVALID_EA_NAME;
+                               _SEH2_LEAVE;
+                       }
+               }
+
+               // Now add EA entries to the inode
+               for (FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
+                       FullEa < (PFILE_FULL_EA_INFORMATION)&UserBuffer[UserBufferLength];
+                       FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ?
+                               &UserBuffer[UserBufferLength] :
+                               (PCHAR)FullEa + FullEa->NextEntryOffset)) {
+
+                               int ret;
+                               OEM_STRING EaName;
+
+                               EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
+                               EaName.Buffer = &FullEa->EaName[0];
+
+                               Status = Ext2WinntError(ret =
+                                       ext4_fs_set_xattr_ordered(&xattr_ref,
+                                               EXT4_XATTR_INDEX_USER,
+                                               EaName.Buffer,
+                                               EaName.Length,
+                                               &FullEa->EaName[0] + FullEa->EaNameLength + 1,
+                                               FullEa->EaValueLength));
+                               if (!NT_SUCCESS(Status))
+                                       _SEH2_LEAVE;
+
+               }
+       } _SEH2_FINALLY {
+
+               if (XattrRefAcquired) {
+                       if (!NT_SUCCESS(Status)) {
+                               xattr_ref.dirty = FALSE;
+                               ext4_fs_put_xattr_ref(&xattr_ref);
+                       } else
+                               Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref));
+               }
+
+               if (FcbLockAcquired) {
+                       ExReleaseResourceLite(&Vcb->FcbLock);
+                       FcbLockAcquired = FALSE;
+               }
+
+               if (MainResourceAcquired) {
+                       ExReleaseResourceLite(&Fcb->MainResource);
+               }
+
+               if (NT_SUCCESS(Status)) {
+                       Ext2NotifyReportChange(
+                               IrpContext,
+                               Vcb,
+                               Mcb,
+                               FILE_NOTIFY_CHANGE_EA,
+                               FILE_ACTION_MODIFIED);
+               }
+
+               if (!_SEH2_AbnormalTermination()) {
+                       if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+                               Status = Ext2QueueRequest(IrpContext);
+                       }
+                       else {
+                               Ext2CompleteIrpContext(IrpContext, Status);
+                       }
+               }
+       } _SEH2_END;
+       return Status;
+}
index 4e38352..377f11f 100644 (file)
@@ -10,7 +10,7 @@
 /* INCLUDES *****************************************************************/
 
 #include "ext2fs.h"
-#include <linux/ext4.h>
+#include "linux/ext4.h"
 
 /* GLOBALS ***************************************************************/
 
@@ -125,23 +125,77 @@ Ext2RefreshSuper (
 }
 
 VOID
-Ext2PutGroup(IN PEXT2_VCB Vcb)
+Ext2DropGroupBH(IN PEXT2_VCB Vcb)
 {
     struct ext3_sb_info *sbi = &Vcb->sbi;
     unsigned long i;
 
-
     if (NULL == Vcb->sbi.s_gd) {
         return;
     }
 
     for (i = 0; i < Vcb->sbi.s_gdb_count; i++) {
-        if (Vcb->sbi.s_gd[i].bh)
+        if (Vcb->sbi.s_gd[i].bh) {
             fini_bh(&sbi->s_gd[i].bh);
+            Vcb->sbi.s_gd[i].bh = NULL;
+        }
     }
+}
+
+VOID
+Ext2PutGroup(IN PEXT2_VCB Vcb)
+{
+    struct ext3_sb_info *sbi = &Vcb->sbi;
+    unsigned long i;
+
+
+    if (NULL == Vcb->sbi.s_gd) {
+        return;
+    }
+
+    Ext2DropGroupBH(Vcb);
 
     kfree(Vcb->sbi.s_gd);
     Vcb->sbi.s_gd = NULL;
+
+    ClearFlag(Vcb->Flags, VCB_GD_LOADED);
+}
+
+
+BOOLEAN
+Ext2LoadGroupBH(IN PEXT2_VCB Vcb)
+{
+    struct super_block  *sb = &Vcb->sb;
+    struct ext3_sb_info *sbi = &Vcb->sbi;
+    unsigned long i;
+    BOOLEAN rc = FALSE;
+
+    _SEH2_TRY {
+
+        ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+        ASSERT (NULL != sbi->s_gd);
+
+        for (i = 0; i < sbi->s_gdb_count; i++) {
+            ASSERT (sbi->s_gd[i].block);
+            if (sbi->s_gd[i].bh)
+                continue;
+            sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block);
+            if (!sbi->s_gd[i].bh) {
+                DEBUG(DL_ERR, ("Ext2LoadGroupBH: can't read group descriptor %d\n", i));
+                DbgBreak();
+                _SEH2_LEAVE;
+            }
+            sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data;
+        }
+
+        rc = TRUE;
+
+    } _SEH2_FINALLY {
+
+        ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+    } _SEH2_END;
+
+    return rc;
 }
 
 
@@ -177,20 +231,20 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb)
                 DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i));
                 _SEH2_LEAVE;
             }
-            sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block);
-            if (!sbi->s_gd[i].bh) {
-                DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i));
-                _SEH2_LEAVE;
-            }
-            sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data;
+        }
+
+        if (!Ext2LoadGroupBH(Vcb)) {
+            DEBUG(DL_ERR, ("Ext2LoadGroup: Failed to load group descriptions !\n"));
+            _SEH2_LEAVE;
         }
 
         if (!ext4_check_descriptors(sb)) {
             DbgBreak();
-            DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted!\n"));
+            DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted !\n"));
             _SEH2_LEAVE;
         }
 
+        SetFlag(Vcb->Flags, VCB_GD_LOADED);
         rc = TRUE;
 
     } _SEH2_FINALLY {
@@ -204,13 +258,10 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb)
     return rc;
 }
 
-
 VOID
 Ext2DropBH(IN PEXT2_VCB Vcb)
 {
     struct ext3_sb_info *sbi = &Vcb->sbi;
-    LARGE_INTEGER        timeout;
-    unsigned long i;
 
     /* do nothing if Vcb is not initialized yet */
     if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED))
@@ -222,15 +273,18 @@ Ext2DropBH(IN PEXT2_VCB Vcb)
         ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
 
         SetFlag(Vcb->Flags, VCB_BEING_DROPPED);
-        Ext2PutGroup(Vcb);
+        Ext2DropGroupBH(Vcb);
 
         while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
             struct buffer_head *bh;
             PLIST_ENTRY         l;
             l = RemoveHeadList(&Vcb->bd.bd_bh_free);
             bh = CONTAINING_RECORD(l, struct buffer_head, b_link);
-            ASSERT(0 == atomic_read(&bh->b_count));
-            free_buffer_head(bh);
+            InitializeListHead(&bh->b_link);
+            if (0 == atomic_read(&bh->b_count)) {
+                buffer_head_remove(&Vcb->bd, bh);
+                free_buffer_head(bh);
+            }
         }
 
     } _SEH2_FINALLY {
@@ -240,6 +294,90 @@ Ext2DropBH(IN PEXT2_VCB Vcb)
     ClearFlag(Vcb->Flags, VCB_BEING_DROPPED);
 }
 
+
+VOID
+Ext2FlushRange(IN PEXT2_VCB Vcb, LARGE_INTEGER s, LARGE_INTEGER e)
+{
+    ULONG len;
+
+    if (e.QuadPart <= s.QuadPart)
+        return;
+
+    /* loop per 2G */
+    while (s.QuadPart < e.QuadPart) {
+        if (e.QuadPart > s.QuadPart + 1024 * 1024 * 1024) {
+            len = 1024 * 1024 * 1024;
+        } else {
+            len = (ULONG) (e.QuadPart - s.QuadPart);
+        }
+        CcFlushCache(&Vcb->SectionObject, &s, len, NULL);
+        s.QuadPart += len;
+    }
+}
+
+NTSTATUS
+Ext2FlushVcb(IN PEXT2_VCB Vcb)
+{
+    LARGE_INTEGER        s = {0}, o;
+    struct ext3_sb_info *sbi = &Vcb->sbi;
+    struct rb_node      *node;
+    struct buffer_head  *bh;
+
+    if (!IsFlagOn(Vcb->Flags, VCB_GD_LOADED)) {
+        CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
+        goto errorout;
+    }
+
+    ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->MainResource));
+
+    _SEH2_TRY {
+
+        /* acqurie gd block */
+        ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+
+        /* acquire bd lock to avoid bh creation */
+        ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+
+        /* drop unused bh */
+        Ext2DropBH(Vcb);
+
+        /* flush volume with all outstanding bh skipped */
+
+        node = rb_first(&Vcb->bd.bd_bh_root);
+        while (node) {
+
+            bh = container_of(node, struct buffer_head, b_rb_node);
+            node = rb_next(node);
+
+            o.QuadPart = bh->b_blocknr << BLOCK_BITS;
+            ASSERT(o.QuadPart >= s.QuadPart);
+
+            if (o.QuadPart == s.QuadPart) {
+                s.QuadPart = s.QuadPart + bh->b_size;
+                continue;
+            }
+
+            if (o.QuadPart > s.QuadPart) {
+                Ext2FlushRange(Vcb, s, o);
+                s.QuadPart = (bh->b_blocknr << BLOCK_BITS) + bh->b_size;
+                continue;
+            }
+        }
+
+        o = Vcb->PartitionInformation.PartitionLength;
+        Ext2FlushRange(Vcb, s, o);
+
+    } _SEH2_FINALLY {
+
+        ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
+        ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+    } _SEH2_END;
+
+errorout:
+    return STATUS_SUCCESS;
+}
+
+
 BOOLEAN
 Ext2SaveGroup(
     IN PEXT2_IRP_CONTEXT    IrpContext,
@@ -326,8 +464,12 @@ void Ext2DecodeInode(struct inode *dst, struct ext3_inode *src)
     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);
+    if (EXT3_HAS_RO_COMPAT_FEATURE(dst->i_sb,
+                                   EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
+        dst->i_extra_isize = src->i_extra_isize;
+    else
+        dst->i_extra_isize = 0;
 }
 
 void Ext2EncodeInode(struct ext3_inode *dst,  struct inode *src)
@@ -352,6 +494,9 @@ void Ext2EncodeInode(struct ext3_inode *dst,  struct inode *src)
     ASSERT(src->i_sb);
     ext3_inode_blocks_set(dst, src);
     memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
+    if (EXT3_HAS_RO_COMPAT_FEATURE(src->i_sb,
+                                   EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
+        dst->i_extra_isize = src->i_extra_isize;
 }
 
 
@@ -359,27 +504,15 @@ BOOLEAN
 Ext2LoadInode (IN PEXT2_VCB Vcb,
                IN struct inode *Inode)
 {
-    struct ext3_inode   ext3i;
-
-    IO_STATUS_BLOCK     IoStatus;
-    LONGLONG            Offset;
+    struct ext3_inode   ext3i = {0};
+    LONGLONG            offset;
 
-    if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset))  {
-        DEBUG(DL_ERR, ( "Ext2LoadInode: error get inode(%xh)'s addr.\n", Inode->i_ino));
+    if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &offset))  {
+        DEBUG(DL_ERR, ("Ext2LoadInode: failed inode %u.\n", Inode->i_ino));
         return FALSE;
     }
 
-    if (!CcCopyRead(
-                Vcb->Volume,
-                (PLARGE_INTEGER)&Offset,
-                sizeof(struct ext3_inode),
-                PIN_WAIT,
-                (PVOID)&ext3i,
-                &IoStatus )) {
-        return FALSE;
-    }
-
-    if (!NT_SUCCESS(IoStatus.Status)) {
+    if (!Ext2LoadBuffer(NULL, Vcb, offset, sizeof(ext3i), &ext3i)) {
         return FALSE;
     }
 
@@ -400,7 +533,7 @@ Ext2ClearInode (
 
     rc = Ext2GetInodeLba(Vcb, Inode, &Offset);
     if (!rc)  {
-        DEBUG(DL_ERR, ( "Ext2SaveInode: error get inode(%xh)'s addr.\n", Inode));
+        DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode));
         goto errorout;
     }
 
@@ -416,9 +549,8 @@ Ext2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext,
                 IN PEXT2_VCB Vcb,
                 IN struct inode *Inode)
 {
-    struct ext3_inode   ext3i;
+    struct ext3_inode   ext3i = {0};
 
-    IO_STATUS_BLOCK     IoStatus;
     LONGLONG            Offset = 0;
     ULONG               InodeSize = sizeof(ext3i);
     BOOLEAN             rc = 0;
@@ -427,24 +559,14 @@ Ext2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext,
                     Inode->i_ino, Inode->i_mode, Inode->i_size));
     rc = Ext2GetInodeLba(Vcb,  Inode->i_ino, &Offset);
     if (!rc)  {
-        DEBUG(DL_ERR, ( "Ext2SaveInode: error get inode(%xh)'s addr.\n", Inode->i_ino));
+        DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode->i_ino));
         goto errorout;
     }
 
-    if (!CcCopyRead(
-                Vcb->Volume,
-                (PLARGE_INTEGER)&Offset,
-                sizeof(struct ext3_inode),
-                PIN_WAIT,
-                (PVOID)&ext3i,
-                &IoStatus )) {
-        rc = FALSE;
-        goto errorout;
-    }
-
-    if (!NT_SUCCESS(IoStatus.Status)) {
-        rc = FALSE;
-        goto errorout;
+    rc = Ext2LoadBuffer(NULL, Vcb, Offset, InodeSize, &ext3i);
+    if (!rc) {
+        DEBUG(DL_ERR, ( "Ext2SaveInode: failed reading inode %u.\n", Inode->i_ino));
+        goto errorout;;
     }
 
     Ext2EncodeInode(&ext3i, Inode);
@@ -460,31 +582,111 @@ errorout:
     return rc;
 }
 
+BOOLEAN
+Ext2LoadInodeXattr(IN PEXT2_VCB Vcb,
+       IN struct inode *Inode,
+       IN PEXT2_INODE InodeXattr)
+{
+       IO_STATUS_BLOCK     IoStatus;
+       LONGLONG            Offset;
+
+       if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset)) {
+               DEBUG(DL_ERR, ("Ext2LoadRawInode: error get inode(%xh)'s addr.\n", Inode->i_ino));
+               return FALSE;
+       }
+
+       if (!CcCopyRead(
+               Vcb->Volume,
+               (PLARGE_INTEGER)&Offset,
+               Vcb->InodeSize,
+               PIN_WAIT,
+               (PVOID)InodeXattr,
+               &IoStatus)) {
+               return FALSE;
+       }
+
+       if (!NT_SUCCESS(IoStatus.Status)) {
+               return FALSE;
+       }
+
+       Ext2EncodeInode(InodeXattr, Inode);
+       return TRUE;
+}
+
+BOOLEAN
+Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext,
+       IN PEXT2_VCB Vcb,
+       IN struct inode *Inode,
+       IN PEXT2_INODE InodeXattr)
+{
+       IO_STATUS_BLOCK     IoStatus;
+       LONGLONG            Offset = 0;
+       ULONG               InodeSize = Vcb->InodeSize;
+       BOOLEAN             rc = 0;
+
+       /* There is no way to put EA information in such a small inode */
+       if (InodeSize == EXT2_GOOD_OLD_INODE_SIZE)
+               return FALSE;
+
+       DEBUG(DL_INF, ("Ext2SaveInodeXattr: Saving Inode %xh: Mode=%xh Size=%xh\n",
+               Inode->i_ino, Inode->i_mode, Inode->i_size));
+       rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset);
+       if (!rc) {
+               DEBUG(DL_ERR, ("Ext2SaveInodeXattr: error get inode(%xh)'s addr.\n", Inode->i_ino));
+               goto errorout;
+       }
+
+       rc = Ext2SaveBuffer(IrpContext,
+                                                                       Vcb,
+                                                                       Offset + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize,
+                                                                       InodeSize - EXT2_GOOD_OLD_INODE_SIZE - Inode->i_extra_isize,
+                                                                       (char *)InodeXattr + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize);
+
+       if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
+               Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
+       }
+
+errorout:
+       return rc;
+}
+
 
 BOOLEAN
 Ext2LoadBlock (IN PEXT2_VCB Vcb,
                IN ULONG     Index,
                IN PVOID     Buffer )
 {
-    IO_STATUS_BLOCK     IoStatus;
-    LONGLONG            Offset;
+    struct buffer_head *bh = NULL;
+    BOOLEAN             rc = 0;
 
-    Offset = (LONGLONG) Index;
-    Offset = Offset * Vcb->BlockSize;
+    _SEH2_TRY {
 
-    if (!CcCopyRead(
-                Vcb->Volume,
-                (PLARGE_INTEGER)&Offset,
-                Vcb->BlockSize,
-                PIN_WAIT,
-                Buffer,
-                &IoStatus ));
+        bh = sb_getblk(&Vcb->sb, (sector_t)Index);
 
-    if (!NT_SUCCESS(IoStatus.Status)) {
-        return FALSE;
-    }
+        if (!bh) {
+            DEBUG(DL_ERR, ("Ext2Loadblock: can't load block %u\n", Index));
+            DbgBreak();
+            _SEH2_LEAVE;
+        }
 
-    return TRUE;
+        if (!buffer_uptodate(bh)) {
+            int err = bh_submit_read(bh);
+               if (err < 0) {
+                   DEBUG(DL_ERR, ("Ext2LoadBlock: reading failed %d\n", err));
+                       _SEH2_LEAVE;
+               }
+        }
+
+        RtlCopyMemory(Buffer, bh->b_data, BLOCK_SIZE);
+        rc = TRUE;
+
+    } _SEH2_FINALLY {
+
+        if (bh)
+            fini_bh(&bh);
+    } _SEH2_END;
+
+    return rc; 
 }
 
 
@@ -494,121 +696,231 @@ Ext2SaveBlock ( IN PEXT2_IRP_CONTEXT    IrpContext,
                 IN ULONG                Index,
                 IN PVOID                Buf )
 {
-    LONGLONG Offset;
-    BOOLEAN  rc;
+    struct buffer_head *bh = NULL;
+    BOOLEAN             rc = 0;
 
-    Offset = (LONGLONG) Index;
-    Offset = Offset * Vcb->BlockSize;
+    _SEH2_TRY {
 
-    rc = Ext2SaveBuffer(IrpContext, Vcb, Offset, Vcb->BlockSize, Buf);
+        bh = sb_getblk_zero(&Vcb->sb, (sector_t)Index);
 
-    if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
-        Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
-    }
+        if (!bh) {
+            DEBUG(DL_ERR, ("Ext2Saveblock: can't load block %u\n", Index));
+            DbgBreak();
+            _SEH2_LEAVE;
+        }
+
+        if (!buffer_uptodate(bh)) {
+        }
+
+        RtlCopyMemory(bh->b_data, Buf, BLOCK_SIZE);
+        mark_buffer_dirty(bh);
+        rc = TRUE;
+
+    } _SEH2_FINALLY {
+
+        if (bh)
+            fini_bh(&bh);
+    } _SEH2_END;
 
     return rc;
 }
 
 BOOLEAN
-Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT    IrpContext,
+Ext2LoadBuffer( IN PEXT2_IRP_CONTEXT    IrpContext,
                 IN PEXT2_VCB            Vcb,
-                IN LONGLONG             Offset,
-                IN ULONG                Size )
+                IN LONGLONG             offset,
+                IN ULONG                size,
+                IN PVOID                buf )
 {
-    PBCB        Bcb;
-    PVOID       Buffer;
-    BOOLEAN     rc;
-
-    if ( !CcPreparePinWrite(
-                Vcb->Volume,
-                (PLARGE_INTEGER) (&Offset),
-                Size,
-                FALSE,
-                PIN_WAIT | PIN_EXCLUSIVE,
-                &Bcb,
-                &Buffer )) {
-
-        DEBUG(DL_ERR, ( "Ext2SaveBuffer: failed to PinLock offset %I64xh ...\n", Offset));
-        return FALSE;
-    }
+    struct buffer_head *bh = NULL;
+    BOOLEAN             rc;
 
     _SEH2_TRY {
 
-        RtlZeroMemory(Buffer, Size);
-        CcSetDirtyPinnedData(Bcb, NULL );
-        SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
+        while (size) {
 
-        rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Size);
-        if (!rc) {
-            DbgBreak();
-            Ext2Sleep(100);
-            rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Size);
+            sector_t    block;
+            ULONG       len = 0, delta = 0;
+
+            block = (sector_t) (offset >> BLOCK_BITS);
+            delta = (ULONG)offset & (BLOCK_SIZE - 1);
+            len = BLOCK_SIZE - delta;
+            if (size < len)
+                len = size;
+
+            bh = sb_getblk(&Vcb->sb, block);
+            if (!bh) {
+                DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
+                DbgBreak();
+                _SEH2_LEAVE;
+            }
+
+            if (!buffer_uptodate(bh)) {
+                   int err = bh_submit_read(bh);
+                   if (err < 0) {
+                           DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
+                           _SEH2_LEAVE;
+                   }
+            }
+
+            _SEH2_TRY {
+                RtlCopyMemory(buf, bh->b_data + delta, len);
+            } _SEH2_FINALLY {
+                fini_bh(&bh);
+            } _SEH2_END;
+
+            buf = (PUCHAR)buf + len;
+            offset = offset + len;
+            size = size - len;
         }
 
+        rc = TRUE;
+
     } _SEH2_FINALLY {
-        CcUnpinData(Bcb);
-    } _SEH2_END;
 
+        if (bh)
+            fini_bh(&bh);
+
+    } _SEH2_END;
 
     return rc;
 }
 
-#define SIZE_256K 0x40000
 
 BOOLEAN
-Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT    IrpContext,
+Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT    IrpContext,
                 IN PEXT2_VCB            Vcb,
-                IN LONGLONG             Offset,
-                IN ULONG                Size,
-                IN PVOID                Buf )
+                IN LONGLONG             offset,
+                IN ULONG                size
+    )
 {
-    BOOLEAN     rc;
+    struct buffer_head *bh = NULL;
+    BOOLEAN             rc = 0;
 
-    while (Size) {
+    _SEH2_TRY {
 
-        PBCB        Bcb;
-        PVOID       Buffer;
-        ULONG       Length;
+        while (size) {
 
-        Length = (ULONG)Offset & (SIZE_256K - 1);
-        Length = SIZE_256K - Length;
-        if (Size < Length)
-            Length = Size;
+            sector_t    block;
+            ULONG       len = 0, delta = 0;
 
-        if ( !CcPreparePinWrite(
-                    Vcb->Volume,
-                    (PLARGE_INTEGER) (&Offset),
-                    Length,
-                    FALSE,
-                    PIN_WAIT | PIN_EXCLUSIVE,
-                    &Bcb,
-                    &Buffer )) {
+            block = (sector_t) (offset >> BLOCK_BITS);
+            delta = (ULONG)offset & (BLOCK_SIZE - 1);
+            len = BLOCK_SIZE - delta;
+            if (size < len)
+                len = size;
 
-            DEBUG(DL_ERR, ( "Ext2SaveBuffer: failed to PinLock offset %I64xh ...\n", Offset));
-            return FALSE;
+            if (delta == 0 && len >= BLOCK_SIZE) {
+                bh = sb_getblk_zero(&Vcb->sb, block);
+            } else {
+                bh = sb_getblk(&Vcb->sb, block);
+            }
+
+            if (!bh) {
+                DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
+                DbgBreak();
+                _SEH2_LEAVE;
+            }
+
+            if (!buffer_uptodate(bh)) {
+                   int err = bh_submit_read(bh);
+                   if (err < 0) {
+                           DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
+                           _SEH2_LEAVE;
+                   }
+            }
+
+            _SEH2_TRY {
+                if (delta == 0 && len >= BLOCK_SIZE) {
+                    /* bh (cache) was already cleaned as zero */
+                } else {
+                    RtlZeroMemory(bh->b_data + delta, len);
+                }
+                mark_buffer_dirty(bh);
+            } _SEH2_FINALLY {
+                fini_bh(&bh);
+            } _SEH2_END;
+
+            offset = offset + len;
+            size = size - len;
         }
 
-        _SEH2_TRY {
+        rc = TRUE;
+
+    } _SEH2_FINALLY {
+
+        if (bh)
+            fini_bh(&bh);
+
+    } _SEH2_END;
+
+    return rc;
+}
+
+
+BOOLEAN
+Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT    IrpContext,
+                IN PEXT2_VCB            Vcb,
+                IN LONGLONG             offset,
+                IN ULONG                size,
+                IN PVOID                buf )
+{
+    struct buffer_head *bh = NULL;
+    BOOLEAN             rc = 0;
+
+    _SEH2_TRY {
+
+        while (size) {
 
-            RtlCopyMemory(Buffer, Buf, Length);
-            CcSetDirtyPinnedData(Bcb, NULL );
-            SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
+            sector_t    block;
+            ULONG       len = 0, delta = 0;
 
-            rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Length);
-            if (!rc) {
+            block = (sector_t) (offset >> BLOCK_BITS);
+            delta = (ULONG)offset & (BLOCK_SIZE - 1);
+            len = BLOCK_SIZE - delta;
+            if (size < len)
+                len = size;
+
+            if (delta == 0 && len >= BLOCK_SIZE) {
+                bh = sb_getblk_zero(&Vcb->sb, block);
+            } else {
+                bh = sb_getblk(&Vcb->sb, block);
+            }
+
+            if (!bh) {
+                DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
                 DbgBreak();
-                Ext2Sleep(100);
-                rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Length);
+                _SEH2_LEAVE;
             }
 
-        } _SEH2_FINALLY {
-            CcUnpinData(Bcb);
-        } _SEH2_END;
+            if (!buffer_uptodate(bh)) {
+                   int err = bh_submit_read(bh);
+                   if (err < 0) {
+                           DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
+                           _SEH2_LEAVE;
+                   }
+            }
 
-        Buf = (PUCHAR)Buf + Length;
-        Offset = Offset + Length;
-        Size = Size - Length;
-    }
+            _SEH2_TRY {
+                RtlCopyMemory(bh->b_data + delta, buf, len);
+                mark_buffer_dirty(bh);
+            } _SEH2_FINALLY {
+                fini_bh(&bh);
+            } _SEH2_END;
+
+            buf = (PUCHAR)buf + len;
+            offset = offset + len;
+            size = size - len;
+        }
+
+        rc = TRUE;
+
+    } _SEH2_FINALLY {
+
+        if (bh)
+            fini_bh(&bh);
+
+    } _SEH2_END;
 
     return rc;
 }
@@ -1522,7 +1834,7 @@ Ext2AddEntry (
     ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
     MainResourceAcquired = TRUE;
 
-     _SEH2_TRY {
+    _SEH2_TRY {
 
         Ext2ReferXcb(&Dcb->ReferenceCount);
         de = Ext2BuildEntry(Vcb, Dcb->Mcb, FileName);
@@ -1661,7 +1973,7 @@ Ext2RemoveEntry (
     ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
     MainResourceAcquired = TRUE;
 
-     _SEH2_TRY {
+    _SEH2_TRY {
 
         Ext2ReferXcb(&Dcb->ReferenceCount);
 
@@ -1682,7 +1994,7 @@ Ext2RemoveEntry (
         rc = ext3_delete_entry(IrpContext, dir, de, bh);
         if (rc) {
             Status = Ext2WinntError(rc);
-             _SEH2_LEAVE;
+            _SEH2_LEAVE;
         }
         /*
                    if (!inode->i_nlink)
@@ -1701,7 +2013,7 @@ Ext2RemoveEntry (
 
         Status = STATUS_SUCCESS;
 
-    }  _SEH2_FINALLY {
+    } _SEH2_FINALLY {
 
         Ext2DerefXcb(&Dcb->ReferenceCount);
 
@@ -2620,11 +2932,15 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
         group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
         offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
 
-        if (!sbi->s_gd || !sbi->s_gd[group].block ||
-            !sbi->s_gd[group].bh) {
+        if (!sbi->s_gd) {
             if (!Ext2LoadGroup(vcb)) {
                 _SEH2_LEAVE;
             }
+        } else if ( !sbi->s_gd[group].block ||
+                    !sbi->s_gd[group].bh) {
+            if (!Ext2LoadGroupBH(vcb)) {
+                _SEH2_LEAVE;
+            }
         }
 
         desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd +
index 4270c15..3ff79bc 100644 (file)
@@ -108,9 +108,12 @@ Ext2RecoverJournal(
     journal_t *             journal = NULL;
     struct ext3_super_block *esb;
 
+    ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
+
     /* check journal inode number */
     if (!Ext2CheckJournal(Vcb, &jNo)) {
-        return -1;
+        rc = -1;
+        goto errorout;
     }
 
     /* allocate journal Mcb */
@@ -168,5 +171,7 @@ errorout:
         Ext2FreeMcb(Vcb, jcb);
     }
 
+    ExReleaseResourceLite(&Vcb->MainResource);
+
     return rc;
 }
index c23557e..4ef64b4 100644 (file)
@@ -2454,6 +2454,7 @@ int ext4_ext_get_blocks(void *icb, handle_t *handle, struct inode *inode, ext4_f
 
        /* allocate new block */
        goal = ext4_ext_find_goal(inode, path, iblock);
+
        newblock = ext4_new_meta_blocks(icb, handle, inode, goal, 0,
                        &allocated, &err);
        if (!newblock)
diff --git a/drivers/filesystems/ext2/src/ext4/ext4_xattr.c b/drivers/filesystems/ext2/src/ext4/ext4_xattr.c
new file mode 100644 (file)
index 0000000..e1a26e9
--- /dev/null
@@ -0,0 +1,1295 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
+ */
+
+#include <ext2fs.h>
+#include <linux/module.h>
+#include <linux/ext4_xattr.h>
+
+static ext4_fsblk_t ext4_new_meta_blocks(void *icb, struct inode *inode,
+       ext4_fsblk_t goal,
+       unsigned int flags,
+       unsigned long *count, int *errp)
+{
+       NTSTATUS status;
+       ULONG blockcnt = (count) ? *count : 1;
+       ULONG block = 0;
+
+       status = Ext2NewBlock((PEXT2_IRP_CONTEXT)icb,
+               inode->i_sb->s_priv,
+               0, (ULONG)goal,
+               &block,
+               &blockcnt);
+       if (count)
+               *count = blockcnt;
+
+       if (!NT_SUCCESS(status)) {
+               *errp = Ext2LinuxError(status);
+               return 0;
+       }
+       inode->i_blocks += (blockcnt * (inode->i_sb->s_blocksize >> 9));
+       return block;
+}
+
+static void ext4_free_blocks(void *icb, struct inode *inode,
+       ext4_fsblk_t block, int count, int flags)
+{
+       Ext2FreeBlock((PEXT2_IRP_CONTEXT)icb, inode->i_sb->s_priv, (ULONG)block, count);
+       inode->i_blocks -= count * (inode->i_sb->s_blocksize >> 9);
+       return;
+}
+
+static inline ext4_fsblk_t ext4_inode_to_goal_block(struct inode *inode)
+{
+       PEXT2_VCB Vcb;
+       Vcb = inode->i_sb->s_priv;
+       return (inode->i_ino - 1) / BLOCKS_PER_GROUP;
+}
+
+#define NAME_HASH_SHIFT 5
+#define VALUE_HASH_SHIFT 16
+
+static inline void ext4_xattr_compute_hash(struct ext4_xattr_header *header,
+                                          struct ext4_xattr_entry *entry)
+{
+       __u32 hash = 0;
+       char *name = EXT4_XATTR_NAME(entry);
+       int n;
+
+       for (n = 0; n < entry->e_name_len; n++) {
+               hash = (hash << NAME_HASH_SHIFT) ^
+                      (hash >> (8 * sizeof(hash) - NAME_HASH_SHIFT)) ^ *name++;
+       }
+
+       if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+               __le32 *value =
+                   (__le32 *)((char *)header + le16_to_cpu(entry->e_value_offs));
+               for (n = (le32_to_cpu(entry->e_value_size) + EXT4_XATTR_ROUND) >>
+                        EXT4_XATTR_PAD_BITS;
+                    n; n--) {
+                       hash = (hash << VALUE_HASH_SHIFT) ^
+                              (hash >> (8 * sizeof(hash) - VALUE_HASH_SHIFT)) ^
+                              le32_to_cpu(*value++);
+               }
+       }
+       entry->e_hash = cpu_to_le32(hash);
+}
+
+#define BLOCK_HASH_SHIFT 16
+
+/*
+ * ext4_xattr_rehash()
+ *
+ * Re-compute the extended attribute hash value after an entry has changed.
+ */
+static void ext4_xattr_rehash(struct ext4_xattr_header *header,
+                             struct ext4_xattr_entry *entry)
+{
+       struct ext4_xattr_entry *here;
+       __u32 hash = 0;
+
+       ext4_xattr_compute_hash(header, entry);
+       here = EXT4_XATTR_ENTRY(header + 1);
+       while (!EXT4_XATTR_IS_LAST_ENTRY(here)) {
+               if (!here->e_hash) {
+                       /* Block is not shared if an entry's hash value == 0 */
+                       hash = 0;
+                       break;
+               }
+               hash = (hash << BLOCK_HASH_SHIFT) ^
+                      (hash >> (8 * sizeof(hash) - BLOCK_HASH_SHIFT)) ^
+                      le32_to_cpu(here->e_hash);
+               here = EXT4_XATTR_NEXT(here);
+       }
+       header->h_hash = cpu_to_le32(hash);
+}
+
+#if CONFIG_META_CSUM_ENABLE
+static __u32
+ext4_xattr_block_checksum(PEXT2_MCB inode_ref,
+                         ext4_fsblk_t blocknr,
+                         struct ext4_xattr_header *header)
+{
+       __u32 checksum = 0;
+       __u64 le64_blocknr = blocknr;
+       struct ext4_sblock *sb = &inode_ref->fs->sb;
+
+       if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
+               __u32 orig_checksum;
+
+               /* Preparation: temporarily set bg checksum to 0 */
+               orig_checksum = header->h_checksum;
+               header->h_checksum = 0;
+               /* First calculate crc32 checksum against fs uuid */
+               checksum = ext4_crc32c(EXT4_CRC32_INIT, sb->uuid,
+                               sizeof(sb->uuid));
+               /* Then calculate crc32 checksum block number */
+               checksum = ext4_crc32c(checksum, &le64_blocknr,
+                                    sizeof(le64_blocknr));
+               /* Finally calculate crc32 checksum against 
+                * the entire xattr block */
+               checksum = ext4_crc32c(checksum, header,
+                                  ext4_sb_get_block_size(sb));
+               header->h_checksum = orig_checksum;
+       }
+       return checksum;
+}
+#else
+#define ext4_xattr_block_checksum(...) 0
+#endif
+
+static void
+ext4_xattr_set_block_checksum(PEXT2_MCB inode_ref,
+                             ext4_fsblk_t blocknr,
+                             struct ext4_xattr_header *header)
+{
+       /* TODO: Need METADATA_CSUM supports. */
+       header->h_checksum = 0;
+}
+
+static int ext4_xattr_item_cmp(struct rb_node *_a,
+                              struct rb_node *_b)
+{
+       int result;
+       struct ext4_xattr_item *a, *b;
+       a = container_of(_a, struct ext4_xattr_item, node);
+       a = container_of(_a, struct ext4_xattr_item, node);
+       b = container_of(_b, struct ext4_xattr_item, node);
+
+       if (a->is_data && !b->is_data)
+               return -1;
+       
+       if (!a->is_data && b->is_data)
+               return 1;
+
+       result = a->name_index - b->name_index;
+       if (result)
+               return result;
+
+       if (a->name_len < b->name_len)
+               return -1;
+
+       if (a->name_len > b->name_len)
+               return 1;
+
+       return memcmp(a->name, b->name, a->name_len);
+}
+
+//
+// Red-black tree insert routine.
+//
+
+static struct ext4_xattr_item *
+ext4_xattr_item_search(struct ext4_xattr_ref *xattr_ref,
+                      struct ext4_xattr_item *name)
+{
+       struct rb_node *new = xattr_ref->root.rb_node;
+
+       while (new) {
+               struct ext4_xattr_item *node =
+                       container_of(new, struct ext4_xattr_item, node);
+               int result = ext4_xattr_item_cmp(&name->node, new);
+
+               if (result < 0)
+                       new = new->rb_left;
+               else if (result > 0)
+                       new = new->rb_right;
+               else
+                       return node;
+
+       }
+
+       return NULL;
+}
+
+static void ext4_xattr_item_insert(struct ext4_xattr_ref *xattr_ref,
+                                  struct ext4_xattr_item *item)
+{
+       rb_insert(&xattr_ref->root, &item->node,
+             ext4_xattr_item_cmp);
+       list_add_tail(&item->list_node, &xattr_ref->ordered_list);
+}
+
+static void ext4_xattr_item_remove(struct ext4_xattr_ref *xattr_ref,
+                                  struct ext4_xattr_item *item)
+{
+       rb_erase(&item->node, &xattr_ref->root);
+       list_del_init(&item->list_node);
+}
+
+static struct ext4_xattr_item *
+ext4_xattr_item_alloc(__u8 name_index, const char *name, size_t name_len)
+{
+       struct ext4_xattr_item *item;
+       item = kzalloc(sizeof(struct ext4_xattr_item) + name_len, GFP_NOFS);
+       if (!item)
+               return NULL;
+
+       item->name_index = name_index;
+       item->name = (char *)(item + 1);
+       item->name_len = name_len;
+       item->data = NULL;
+       item->data_size = 0;
+       INIT_LIST_HEAD(&item->list_node);
+
+       memcpy(item->name, name, name_len);
+
+       if (name_index == EXT4_XATTR_INDEX_SYSTEM &&
+           name_len == 4 &&
+           !memcmp(name, "data", 4))
+               item->is_data = TRUE;
+       else
+               item->is_data = FALSE;
+
+       return item;
+}
+
+static int ext4_xattr_item_alloc_data(struct ext4_xattr_item *item,
+                                     const void *orig_data, size_t data_size)
+{
+       void *data = NULL;
+       ASSERT(!item->data);
+       data = kmalloc(data_size, GFP_NOFS);
+       if (!data)
+               return -ENOMEM;
+
+       if (orig_data)
+               memcpy(data, orig_data, data_size);
+
+       item->data = data;
+       item->data_size = data_size;
+       return 0;
+}
+
+static void ext4_xattr_item_free_data(struct ext4_xattr_item *item)
+{
+       ASSERT(item->data);
+       kfree(item->data);
+       item->data = NULL;
+       item->data_size = 0;
+}
+
+static int ext4_xattr_item_resize_data(struct ext4_xattr_item *item,
+                                      size_t new_data_size)
+{
+       if (new_data_size != item->data_size) {
+               void *new_data;
+               new_data = kmalloc(new_data_size, GFP_NOFS);
+               if (!new_data)
+                       return -ENOMEM;
+
+               memcpy(new_data, item->data, item->data_size);
+               kfree(item->data);
+
+               item->data = new_data;
+               item->data_size = new_data_size;
+       }
+       return 0;
+}
+
+static void ext4_xattr_item_free(struct ext4_xattr_item *item)
+{
+       if (item->data)
+               ext4_xattr_item_free_data(item);
+
+       kfree(item);
+}
+
+static void *ext4_xattr_entry_data(struct ext4_xattr_ref *xattr_ref,
+                                  struct ext4_xattr_entry *entry,
+                                  BOOL in_inode)
+{
+       char *ret;
+       int block_size;
+       if (in_inode) {
+               struct ext4_xattr_ibody_header *header;
+               struct ext4_xattr_entry *first_entry;
+               int inode_size = xattr_ref->fs->InodeSize;
+               header = EXT4_XATTR_IHDR(xattr_ref->OnDiskInode);
+               first_entry = EXT4_XATTR_IFIRST(header);
+
+               ret = ((char *)first_entry + le16_to_cpu(entry->e_value_offs));
+               if (ret + EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) -
+                       (char *)xattr_ref->OnDiskInode > inode_size)
+                       ret = NULL;
+
+               return ret;
+
+       }
+       block_size = xattr_ref->fs->BlockSize;
+       ret = ((char *)xattr_ref->block_bh->b_data + le16_to_cpu(entry->e_value_offs));
+       if (ret + EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) -
+                       (char *)xattr_ref->block_bh->b_data > block_size)
+               ret = NULL;
+       return ret;
+}
+
+static int ext4_xattr_block_fetch(struct ext4_xattr_ref *xattr_ref)
+{
+       int ret = 0;
+       size_t size_rem;
+       void *data;
+       struct ext4_xattr_entry *entry = NULL;
+
+       ASSERT(xattr_ref->block_bh->b_data);
+       entry = EXT4_XATTR_BFIRST(xattr_ref->block_bh);
+
+       size_rem = xattr_ref->fs->BlockSize;
+       for (; size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry);
+            entry = EXT4_XATTR_NEXT(entry),
+            size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) {
+               struct ext4_xattr_item *item;
+               char *e_name = EXT4_XATTR_NAME(entry);
+
+               data = ext4_xattr_entry_data(xattr_ref, entry, FALSE);
+               if (!data) {
+                       ret = -EIO;
+                       goto Finish;
+               }
+
+               item = ext4_xattr_item_alloc(entry->e_name_index, e_name,
+                                            (size_t)entry->e_name_len);
+               if (!item) {
+                       ret = -ENOMEM;
+                       goto Finish;
+               }
+               if (ext4_xattr_item_alloc_data(
+                       item, data, le32_to_cpu(entry->e_value_size)) != 0) {
+                       ext4_xattr_item_free(item);
+                       ret = -ENOMEM;
+                       goto Finish;
+               }
+               ext4_xattr_item_insert(xattr_ref, item);
+               xattr_ref->block_size_rem -=
+                       EXT4_XATTR_SIZE(item->data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+               xattr_ref->ea_size += EXT4_XATTR_SIZE(item->data_size) +
+                                     EXT4_XATTR_LEN(item->name_len);
+       }
+
+Finish:
+       return ret;
+}
+
+static int ext4_xattr_inode_fetch(struct ext4_xattr_ref *xattr_ref)
+{
+       void *data;
+       size_t size_rem;
+       int ret = 0;
+       struct ext4_xattr_ibody_header *header = NULL;
+       struct ext4_xattr_entry *entry = NULL;
+       int inode_size = xattr_ref->fs->InodeSize;
+
+       header = EXT4_XATTR_IHDR(xattr_ref->OnDiskInode);
+       entry = EXT4_XATTR_IFIRST(header);
+
+       size_rem = inode_size - EXT4_GOOD_OLD_INODE_SIZE -
+                  xattr_ref->OnDiskInode->i_extra_isize;
+       for (; size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry);
+            entry = EXT4_XATTR_NEXT(entry),
+            size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) {
+               struct ext4_xattr_item *item;
+               char *e_name = EXT4_XATTR_NAME(entry);
+
+               data = ext4_xattr_entry_data(xattr_ref, entry, TRUE);
+               if (!data) {
+                       ret = -EIO;
+                       goto Finish;
+               }
+
+               item = ext4_xattr_item_alloc(entry->e_name_index, e_name,
+                                            (size_t)entry->e_name_len);
+               if (!item) {
+                       ret = -ENOMEM;
+                       goto Finish;
+               }
+               if (ext4_xattr_item_alloc_data(
+                       item, data, le32_to_cpu(entry->e_value_size)) != 0) {
+                       ext4_xattr_item_free(item);
+                       ret = -ENOMEM;
+                       goto Finish;
+               }
+               item->in_inode = TRUE;
+               ext4_xattr_item_insert(xattr_ref, item);
+               xattr_ref->inode_size_rem -=
+                       EXT4_XATTR_SIZE(item->data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+               xattr_ref->ea_size += EXT4_XATTR_SIZE(item->data_size) +
+                                     EXT4_XATTR_LEN(item->name_len);
+       }
+
+Finish:
+       return ret;
+}
+
+static __s32 ext4_xattr_inode_space(struct ext4_xattr_ref *xattr_ref)
+{
+       int inode_size = xattr_ref->fs->InodeSize;
+       int size_rem = inode_size - EXT4_GOOD_OLD_INODE_SIZE -
+                           xattr_ref->OnDiskInode->i_extra_isize;
+       return size_rem;
+}
+
+static __s32 ext4_xattr_block_space(struct ext4_xattr_ref *xattr_ref)
+{
+       return xattr_ref->fs->BlockSize;
+}
+
+static int ext4_xattr_fetch(struct ext4_xattr_ref *xattr_ref)
+{
+       int ret = 0;
+       int inode_size = xattr_ref->fs->InodeSize;
+       if (inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
+               ret = ext4_xattr_inode_fetch(xattr_ref);
+               if (ret != 0)
+                       return ret;
+       }
+
+       if (xattr_ref->block_loaded)
+               ret = ext4_xattr_block_fetch(xattr_ref);
+
+       xattr_ref->dirty = FALSE;
+       return ret;
+}
+
+static struct ext4_xattr_item *
+ext4_xattr_lookup_item(struct ext4_xattr_ref *xattr_ref, __u8 name_index,
+                      const char *name, size_t name_len)
+{
+       struct ext4_xattr_item tmp = {
+               FALSE,
+               FALSE,
+               name_index,
+               (char *)name, /*won't touch this string*/
+               name_len,
+       };
+       if (name_index == EXT4_XATTR_INDEX_SYSTEM &&
+           name_len == 4 &&
+           !memcmp(name, "data", 4))
+               tmp.is_data = TRUE;
+
+       return ext4_xattr_item_search(xattr_ref, &tmp);
+}
+
+static struct ext4_xattr_item *
+ext4_xattr_insert_item(struct ext4_xattr_ref *xattr_ref, __u8 name_index,
+                      const char *name, size_t name_len, const void *data,
+                      size_t data_size,
+                      int *err)
+{
+       struct ext4_xattr_item *item;
+       item = ext4_xattr_item_alloc(name_index, name, name_len);
+       if (!item) {
+               if (err)
+                       *err = -ENOMEM;
+
+               return NULL;
+       }
+
+       item->in_inode = TRUE;
+       if (xattr_ref->inode_size_rem <
+          EXT4_XATTR_SIZE(data_size) +
+          EXT4_XATTR_LEN(item->name_len)) {
+               if (xattr_ref->block_size_rem <
+                  EXT4_XATTR_SIZE(data_size) +
+                  EXT4_XATTR_LEN(item->name_len)) {
+                       if (err)
+                               *err = -ENOSPC;
+
+                       return NULL;
+               }
+
+               item->in_inode = FALSE;
+       }
+       if (ext4_xattr_item_alloc_data(item, data, data_size) != 0) {
+               ext4_xattr_item_free(item);
+               if (err)
+                       *err = -ENOMEM;
+
+               return NULL;
+       }
+       ext4_xattr_item_insert(xattr_ref, item);
+       xattr_ref->ea_size +=
+           EXT4_XATTR_SIZE(item->data_size) + EXT4_XATTR_LEN(item->name_len);
+       if (item->in_inode) {
+               xattr_ref->inode_size_rem -=
+                       EXT4_XATTR_SIZE(item->data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+       } else {
+               xattr_ref->block_size_rem -=
+                       EXT4_XATTR_SIZE(item->data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+       }
+       xattr_ref->dirty = TRUE;
+       if (err)
+               *err = 0;
+
+       return item;
+}
+
+static struct ext4_xattr_item *
+ext4_xattr_insert_item_ordered(struct ext4_xattr_ref *xattr_ref, __u8 name_index,
+       const char *name, size_t name_len, const void *data,
+       size_t data_size,
+       int *err)
+{
+       struct ext4_xattr_item *item, *last_item = NULL;
+       item = ext4_xattr_item_alloc(name_index, name, name_len);
+       if (!item) {
+               if (err)
+                       *err = -ENOMEM;
+
+               return NULL;
+       }
+
+       if (!list_empty(&xattr_ref->ordered_list))
+               last_item = list_entry(xattr_ref->ordered_list.prev,
+                                       struct ext4_xattr_item,
+                                       list_node);
+
+       item->in_inode = TRUE;
+       if ((xattr_ref->inode_size_rem <
+               EXT4_XATTR_SIZE(data_size) +
+               EXT4_XATTR_LEN(item->name_len))
+                       ||
+               (last_item && !last_item->in_inode)) {
+               if (xattr_ref->block_size_rem <
+                       EXT4_XATTR_SIZE(data_size) +
+                       EXT4_XATTR_LEN(item->name_len)) {
+                       if (err)
+                               *err = -ENOSPC;
+
+                       return NULL;
+               }
+
+               item->in_inode = FALSE;
+       }
+       if (ext4_xattr_item_alloc_data(item, data, data_size) != 0) {
+               ext4_xattr_item_free(item);
+               if (err)
+                       *err = -ENOMEM;
+
+               return NULL;
+       }
+       ext4_xattr_item_insert(xattr_ref, item);
+       xattr_ref->ea_size +=
+               EXT4_XATTR_SIZE(item->data_size) + EXT4_XATTR_LEN(item->name_len);
+       if (item->in_inode) {
+               xattr_ref->inode_size_rem -=
+                       EXT4_XATTR_SIZE(item->data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+       }
+       else {
+               xattr_ref->block_size_rem -=
+                       EXT4_XATTR_SIZE(item->data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+       }
+       xattr_ref->dirty = TRUE;
+       if (err)
+               *err = 0;
+
+       return item;
+}
+
+static int ext4_xattr_remove_item(struct ext4_xattr_ref *xattr_ref,
+                                 __u8 name_index, const char *name,
+                                 size_t name_len)
+{
+       int ret = -ENOENT;
+       struct ext4_xattr_item *item =
+           ext4_xattr_lookup_item(xattr_ref, name_index, name, name_len);
+       if (item) {
+               if (item == xattr_ref->iter_from) {
+                       struct rb_node *next_node;
+                       next_node = rb_next(&item->node);
+                       if (next_node)
+                               xattr_ref->iter_from =
+                                       container_of(next_node,
+                                                    struct ext4_xattr_item,
+                                                    node);
+                       else
+                               xattr_ref->iter_from = NULL;
+               }
+
+               xattr_ref->ea_size -= EXT4_XATTR_SIZE(item->data_size) +
+                                     EXT4_XATTR_LEN(item->name_len);
+
+               if (item->in_inode) {
+                       xattr_ref->inode_size_rem +=
+                               EXT4_XATTR_SIZE(item->data_size) +
+                               EXT4_XATTR_LEN(item->name_len);
+               } else {
+                       xattr_ref->block_size_rem +=
+                               EXT4_XATTR_SIZE(item->data_size) +
+                               EXT4_XATTR_LEN(item->name_len);
+               }
+
+               ext4_xattr_item_remove(xattr_ref, item);
+               ext4_xattr_item_free(item);
+               xattr_ref->dirty = TRUE;
+               ret = 0;
+       }
+       return ret;
+}
+
+static int ext4_xattr_resize_item(struct ext4_xattr_ref *xattr_ref,
+                                 struct ext4_xattr_item *item,
+                                 size_t new_data_size)
+{
+       int ret = 0;
+       BOOL to_inode = FALSE, to_block = FALSE;
+       size_t old_data_size = item->data_size;
+       size_t orig_room_size = item->in_inode ?
+               xattr_ref->inode_size_rem :
+               xattr_ref->block_size_rem;
+
+       /*
+        * Check if we can hold this entry in both in-inode and
+        * on-block form
+        *
+        * More complicated case: we do not allow entries stucking in
+        * the middle between in-inode space and on-block space, so
+        * the entry has to stay in either inode space or block space.
+        */
+       if (item->in_inode) {
+               if (xattr_ref->inode_size_rem +
+                              EXT4_XATTR_SIZE(old_data_size) <
+                              EXT4_XATTR_SIZE(new_data_size)) {
+                       if (xattr_ref->block_size_rem <
+                                      EXT4_XATTR_SIZE(new_data_size) +
+                                      EXT4_XATTR_LEN(item->name_len))
+                               return -ENOSPC;
+
+                       to_block = TRUE;
+               }
+       } else {
+               if (xattr_ref->block_size_rem +
+                               EXT4_XATTR_SIZE(old_data_size) <
+                               EXT4_XATTR_SIZE(new_data_size)) {
+                       if (xattr_ref->inode_size_rem <
+                                       EXT4_XATTR_SIZE(new_data_size) +
+                                       EXT4_XATTR_LEN(item->name_len))
+                               return -ENOSPC;
+
+                       to_inode = TRUE;
+               }
+       }
+       ret = ext4_xattr_item_resize_data(item, new_data_size);
+       if (ret)
+               return ret;
+
+       xattr_ref->ea_size =
+           xattr_ref->ea_size -
+           EXT4_XATTR_SIZE(old_data_size) +
+           EXT4_XATTR_SIZE(new_data_size);
+
+       /*
+        * This entry may originally lie in inode space or block space,
+        * and it is going to be transferred to another place.
+        */
+       if (to_block) {
+               xattr_ref->inode_size_rem +=
+                       EXT4_XATTR_SIZE(old_data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+               xattr_ref->block_size_rem -=
+                       EXT4_XATTR_SIZE(new_data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+               item->in_inode = FALSE;
+       } else if (to_inode) {
+               xattr_ref->block_size_rem +=
+                       EXT4_XATTR_SIZE(old_data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+               xattr_ref->inode_size_rem -=
+                       EXT4_XATTR_SIZE(new_data_size) +
+                       EXT4_XATTR_LEN(item->name_len);
+               item->in_inode = TRUE;
+       } else {
+               /*
+                * No need to transfer as there is enough space for the entry
+                * to stay in inode space or block space it used to be.
+                */
+               orig_room_size +=
+                       EXT4_XATTR_SIZE(old_data_size);
+               orig_room_size -=
+                       EXT4_XATTR_SIZE(new_data_size);
+               if (item->in_inode)
+                       xattr_ref->inode_size_rem = orig_room_size;
+               else
+                       xattr_ref->block_size_rem = orig_room_size;
+
+       }
+       xattr_ref->dirty = TRUE;
+       return ret;
+}
+
+void ext4_xattr_purge_items(struct ext4_xattr_ref *xattr_ref)
+{
+       struct rb_node *first_node;
+       struct ext4_xattr_item *item = NULL;
+       first_node = rb_first(&xattr_ref->root);
+       if (first_node)
+               item = container_of(first_node, struct ext4_xattr_item,
+                                   node);
+
+       while (item) {
+               struct rb_node *next_node;
+               struct ext4_xattr_item *next_item = NULL;
+               next_node = rb_next(&item->node);
+               if (next_node)
+                       next_item = container_of(next_node, struct ext4_xattr_item,
+                                                node);
+               else
+                       next_item = NULL;
+
+               ext4_xattr_item_remove(xattr_ref, item);
+               ext4_xattr_item_free(item);
+
+               item = next_item;
+       }
+       xattr_ref->ea_size = 0;
+       if (ext4_xattr_inode_space(xattr_ref) <
+          sizeof(struct ext4_xattr_ibody_header))
+               xattr_ref->inode_size_rem = 0;
+       else
+               xattr_ref->inode_size_rem =
+                      ext4_xattr_inode_space(xattr_ref) -
+                      sizeof(struct ext4_xattr_ibody_header);
+
+       xattr_ref->block_size_rem =
+               ext4_xattr_block_space(xattr_ref) -
+               sizeof(struct ext4_xattr_header);
+}
+
+static int ext4_xattr_try_alloc_block(struct ext4_xattr_ref *xattr_ref)
+{
+       int ret = 0;
+
+       ext4_fsblk_t xattr_block = 0;
+       xattr_block = xattr_ref->inode_ref->Inode.i_file_acl;
+       if (!xattr_block) {
+               ext4_fsblk_t goal =
+                       ext4_inode_to_goal_block(&xattr_ref->inode_ref->Inode);
+
+               xattr_block = ext4_new_meta_blocks(xattr_ref->IrpContext,
+                                                 &xattr_ref->inode_ref->Inode,
+                                             goal, 0, NULL,
+                                             &ret);
+               if (ret != 0)
+                       goto Finish;
+
+               xattr_ref->block_bh = extents_bwrite(&xattr_ref->fs->sb, xattr_block);
+               if (!xattr_ref->block_bh) {
+                       ext4_free_blocks(xattr_ref->IrpContext, &xattr_ref->inode_ref->Inode,
+                                              xattr_block, 1, 0);
+                       ret = -ENOMEM;
+                       goto Finish;
+               }
+
+               xattr_ref->inode_ref->Inode.i_file_acl = xattr_block;
+               xattr_ref->IsOnDiskInodeDirty = TRUE;
+               xattr_ref->block_loaded = TRUE;
+       }
+
+Finish:
+       return ret;
+}
+
+static void ext4_xattr_try_free_block(struct ext4_xattr_ref *xattr_ref)
+{
+       ext4_fsblk_t xattr_block;
+       xattr_block = xattr_ref->inode_ref->Inode.i_file_acl;
+       xattr_ref->inode_ref->Inode.i_file_acl = 0;
+       extents_brelse(xattr_ref->block_bh);
+       xattr_ref->block_bh = NULL;
+       ext4_free_blocks(xattr_ref->IrpContext, &xattr_ref->inode_ref->Inode,
+               xattr_block, 1, 0);
+       xattr_ref->IsOnDiskInodeDirty = TRUE;
+       xattr_ref->block_loaded = FALSE;
+}
+
+static void ext4_xattr_set_block_header(struct ext4_xattr_ref *xattr_ref)
+{
+       struct ext4_xattr_header *block_header = NULL;
+       block_header = EXT4_XATTR_BHDR(xattr_ref->block_bh);
+
+       memset(block_header, 0, sizeof(struct ext4_xattr_header));
+       block_header->h_magic = EXT4_XATTR_MAGIC;
+       block_header->h_refcount = cpu_to_le32(1);
+       block_header->h_blocks = cpu_to_le32(1);
+}
+
+static void
+ext4_xattr_set_inode_entry(struct ext4_xattr_item *item,
+                          struct ext4_xattr_ibody_header *ibody_header,
+                          struct ext4_xattr_entry *entry, void *ibody_data_ptr)
+{
+       entry->e_name_len = (__u8)item->name_len;
+       entry->e_name_index = item->name_index;
+       entry->e_value_offs =
+          cpu_to_le16((char *)ibody_data_ptr - (char *)EXT4_XATTR_IFIRST(ibody_header));
+       entry->e_value_block = 0;
+       entry->e_value_size = cpu_to_le32(item->data_size);
+}
+
+static void ext4_xattr_set_block_entry(struct ext4_xattr_item *item,
+                                      struct ext4_xattr_header *block_header,
+                                      struct ext4_xattr_entry *block_entry,
+                                      void *block_data_ptr)
+{
+       block_entry->e_name_len = (__u8)item->name_len;
+       block_entry->e_name_index = item->name_index;
+       block_entry->e_value_offs =
+           cpu_to_le16((char *)block_data_ptr - (char *)block_header);
+       block_entry->e_value_block = 0;
+       block_entry->e_value_size = cpu_to_le32(item->data_size);
+}
+
+static int ext4_xattr_write_to_disk(struct ext4_xattr_ref *xattr_ref)
+{
+       int ret = 0;
+       BOOL block_modified = FALSE;
+       void *ibody_data = NULL;
+       void *block_data = NULL;
+       size_t inode_size_rem, block_size_rem;
+       struct ext4_xattr_ibody_header *ibody_header = NULL;
+       struct ext4_xattr_header *block_header = NULL;
+       struct ext4_xattr_entry *entry = NULL;
+       struct ext4_xattr_entry *block_entry = NULL;
+       struct ext4_xattr_item *item = NULL;
+
+       inode_size_rem = ext4_xattr_inode_space(xattr_ref);
+       block_size_rem = ext4_xattr_block_space(xattr_ref);
+       if (inode_size_rem > sizeof(struct ext4_xattr_ibody_header)) {
+               ibody_header = EXT4_XATTR_IHDR(xattr_ref->OnDiskInode);
+               entry = EXT4_XATTR_IFIRST(ibody_header);
+       }
+
+       if (!xattr_ref->dirty)
+               goto Finish;
+       /* If there are enough spaces in the ibody EA table.*/
+       if (inode_size_rem > sizeof(struct ext4_xattr_ibody_header)) {
+               memset(ibody_header, 0, inode_size_rem);
+               ibody_header->h_magic = EXT4_XATTR_MAGIC;
+               ibody_data = (char *)ibody_header + inode_size_rem;
+               inode_size_rem -= sizeof(struct ext4_xattr_ibody_header);
+
+               xattr_ref->IsOnDiskInodeDirty = TRUE;
+       }
+       /* If we need an extra block to hold the EA entries*/
+       if (xattr_ref->ea_size > inode_size_rem) {
+               if (!xattr_ref->block_loaded) {
+                       ret = ext4_xattr_try_alloc_block(xattr_ref);
+                       if (ret != 0)
+                               goto Finish;
+               }
+               memset(xattr_ref->block_bh->b_data, 0, xattr_ref->fs->BlockSize);
+               block_header = EXT4_XATTR_BHDR(xattr_ref->block_bh);
+               block_entry = EXT4_XATTR_BFIRST(xattr_ref->block_bh);
+               ext4_xattr_set_block_header(xattr_ref);
+               block_data = (char *)block_header + block_size_rem;
+               block_size_rem -= sizeof(struct ext4_xattr_header);
+
+               extents_mark_buffer_dirty(xattr_ref->block_bh);
+       } else {
+               /* We don't need an extra block.*/
+               if (xattr_ref->block_loaded) {
+                       block_header = EXT4_XATTR_BHDR(xattr_ref->block_bh);
+                       le32_add_cpu(&block_header->h_refcount, -1);
+                       if (!block_header->h_refcount) {
+                               ext4_xattr_try_free_block(xattr_ref);
+                               block_header = NULL;
+                       } else {
+                               block_entry =
+                                   EXT4_XATTR_BFIRST(xattr_ref->block_bh);
+                               block_data =
+                                   (char *)block_header + block_size_rem;
+                               block_size_rem -=
+                                   sizeof(struct ext4_xattr_header);
+                               xattr_ref->inode_ref->Inode.i_file_acl = 0;
+
+                               xattr_ref->IsOnDiskInodeDirty = TRUE;
+                               extents_mark_buffer_dirty(xattr_ref->block_bh);
+                       }
+               }
+       }
+
+       list_for_each_entry(item, &xattr_ref->ordered_list, struct ext4_xattr_item, list_node) {
+               if (item->in_inode) {
+                       ibody_data = (char *)ibody_data -
+                                    EXT4_XATTR_SIZE(item->data_size);
+                       ext4_xattr_set_inode_entry(item, ibody_header, entry,
+                                                  ibody_data);
+                       memcpy(EXT4_XATTR_NAME(entry), item->name,
+                              item->name_len);
+                       memcpy(ibody_data, item->data, item->data_size);
+                       entry = EXT4_XATTR_NEXT(entry);
+                       inode_size_rem -= EXT4_XATTR_SIZE(item->data_size) +
+                                         EXT4_XATTR_LEN(item->name_len);
+
+                       xattr_ref->IsOnDiskInodeDirty = TRUE;
+                       continue;
+               }
+               if (EXT4_XATTR_SIZE(item->data_size) +
+                       EXT4_XATTR_LEN(item->name_len) >
+                   block_size_rem) {
+                       ret = -ENOSPC;
+                       DbgPrint("ext4_xattr.c: IMPOSSIBLE -ENOSPC AS WE DID INSPECTION!\n");
+                       ASSERT(0);
+               }
+               block_data =
+                   (char *)block_data - EXT4_XATTR_SIZE(item->data_size);
+               ext4_xattr_set_block_entry(item, block_header, block_entry,
+                                          block_data);
+               memcpy(EXT4_XATTR_NAME(block_entry), item->name,
+                      item->name_len);
+               memcpy(block_data, item->data, item->data_size);
+               ext4_xattr_compute_hash(block_header, block_entry);
+               block_entry = EXT4_XATTR_NEXT(block_entry);
+               block_size_rem -= EXT4_XATTR_SIZE(item->data_size) +
+                                 EXT4_XATTR_LEN(item->name_len);
+
+               block_modified = TRUE;
+       }
+       xattr_ref->dirty = FALSE;
+       if (block_modified) {
+               ext4_xattr_rehash(block_header,
+                                 EXT4_XATTR_BFIRST(xattr_ref->block_bh));
+               ext4_xattr_set_block_checksum(xattr_ref->inode_ref,
+                                             xattr_ref->block_bh->b_blocknr,
+                                             block_header);
+               extents_mark_buffer_dirty(xattr_ref->block_bh);
+       }
+
+Finish:
+       return ret;
+}
+
+void ext4_fs_xattr_iterate(struct ext4_xattr_ref *ref,
+                          int (*iter)(struct ext4_xattr_ref *ref,
+                                    struct ext4_xattr_item *item,
+                                        BOOL is_last))
+{
+       struct ext4_xattr_item *item;
+       if (!ref->iter_from) {
+               struct list_head *first_node;
+               first_node = ref->ordered_list.next;
+               if (first_node && first_node != &ref->ordered_list) {
+                       ref->iter_from =
+                               list_entry(first_node,
+                                            struct ext4_xattr_item,
+                                            list_node);
+               }
+       }
+
+       item = ref->iter_from;
+       while (item) {
+               struct list_head *next_node;
+               struct ext4_xattr_item *next_item;
+               int ret = EXT4_XATTR_ITERATE_CONT;
+               next_node = item->list_node.next;
+               if (next_node && next_node != &ref->ordered_list)
+                       next_item = list_entry(next_node, struct ext4_xattr_item,
+                                                list_node);
+               else
+                       next_item = NULL;
+               if (iter)
+                       ret = iter(ref, item, !next_item);
+
+               if (ret != EXT4_XATTR_ITERATE_CONT) {
+                       if (ret == EXT4_XATTR_ITERATE_STOP)
+                               ref->iter_from = NULL;
+
+                       break;
+               }
+               item = next_item;
+       }
+}
+
+void ext4_fs_xattr_iterate_reset(struct ext4_xattr_ref *ref)
+{
+       ref->iter_from = NULL;
+}
+
+int ext4_fs_set_xattr(struct ext4_xattr_ref *ref, __u8 name_index,
+                     const char *name, size_t name_len, const void *data,
+                     size_t data_size, BOOL replace)
+{
+       int ret = 0;
+       struct ext4_xattr_item *item =
+           ext4_xattr_lookup_item(ref, name_index, name, name_len);
+       if (replace) {
+               if (!item) {
+                       ret = -ENODATA;
+                       goto Finish;
+               }
+               if (item->data_size != data_size)
+                       ret = ext4_xattr_resize_item(ref, item, data_size);
+
+               if (ret != 0) {
+                       goto Finish;
+               }
+               memcpy(item->data, data, data_size);
+       } else {
+               if (item) {
+                       ret = -EEXIST;
+                       goto Finish;
+               }
+               item = ext4_xattr_insert_item(ref, name_index, name, name_len,
+                                             data, data_size, &ret);
+       }
+Finish:
+       return ret;
+}
+
+int ext4_fs_set_xattr_ordered(struct ext4_xattr_ref *ref, __u8 name_index,
+       const char *name, size_t name_len, const void *data,
+       size_t data_size)
+{
+       int ret = 0;
+       struct ext4_xattr_item *item =
+               ext4_xattr_lookup_item(ref, name_index, name, name_len);
+       if (item) {
+               ret = -EEXIST;
+               goto Finish;
+       }
+       item = ext4_xattr_insert_item_ordered(ref, name_index, name, name_len,
+               data, data_size, &ret);
+Finish:
+       return ret;
+}
+
+int ext4_fs_remove_xattr(struct ext4_xattr_ref *ref, __u8 name_index,
+                        const char *name, size_t name_len)
+{
+       return ext4_xattr_remove_item(ref, name_index, name, name_len);
+}
+
+int ext4_fs_get_xattr(struct ext4_xattr_ref *ref, __u8 name_index,
+                     const char *name, size_t name_len, void *buf,
+                     size_t buf_size, size_t *data_size)
+{
+       int ret = 0;
+       size_t item_size = 0;
+       struct ext4_xattr_item *item =
+           ext4_xattr_lookup_item(ref, name_index, name, name_len);
+
+       if (!item) {
+               ret = -ENODATA;
+               goto Finish;
+       }
+       item_size = item->data_size;
+       if (buf_size > item_size)
+               buf_size = item_size;
+
+       if (buf)
+               memcpy(buf, item->data, buf_size);
+
+Finish:
+       if (data_size)
+               *data_size = item_size;
+
+       return ret;
+}
+
+int ext4_fs_get_xattr_ref(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB fs, PEXT2_MCB inode_ref,
+                         struct ext4_xattr_ref *ref)
+{
+       int rc;
+       ext4_fsblk_t xattr_block;
+       xattr_block = inode_ref->Inode.i_file_acl;
+       memset(&ref->root, 0, sizeof(struct rb_root));
+       ref->ea_size = 0;
+       ref->iter_from = NULL;
+       if (xattr_block) {
+               ref->block_bh = extents_bread(&fs->sb, xattr_block);
+               if (!ref->block_bh)
+                       return -EIO;
+
+               ref->block_loaded = TRUE;
+       } else
+               ref->block_loaded = FALSE;
+
+       ref->inode_ref = inode_ref;
+       ref->fs = fs;
+       INIT_LIST_HEAD(&ref->ordered_list);
+
+       ref->OnDiskInode = Ext2AllocateInode(fs);
+       if (!ref->OnDiskInode) {
+               if (xattr_block) {
+                       extents_brelse(ref->block_bh);
+                       ref->block_bh = NULL;
+               }
+               return -ENOMEM;
+       }
+       if (!Ext2LoadInodeXattr(fs, &inode_ref->Inode, ref->OnDiskInode)) {
+               if (xattr_block) {
+                       extents_brelse(ref->block_bh);
+                       ref->block_bh = NULL;
+               }
+
+               Ext2DestroyInode(fs, ref->OnDiskInode);
+               return -EIO;
+       }
+       ref->IsOnDiskInodeDirty = FALSE;
+
+       if (ext4_xattr_inode_space(ref) <
+          sizeof(struct ext4_xattr_ibody_header) +
+          sizeof(__u32))
+               ref->inode_size_rem = 0;
+       else {
+               ref->inode_size_rem =
+                       ext4_xattr_inode_space(ref) -
+                       sizeof(struct ext4_xattr_ibody_header);
+       }
+
+       ref->block_size_rem =
+               ext4_xattr_block_space(ref) -
+               sizeof(struct ext4_xattr_header) -
+               sizeof(__u32);
+
+       rc = ext4_xattr_fetch(ref);
+       if (rc != 0) {
+               ext4_xattr_purge_items(ref);
+               if (xattr_block) {
+                       extents_brelse(ref->block_bh);
+                       ref->block_bh = NULL;
+               }
+
+               Ext2DestroyInode(fs, ref->OnDiskInode);
+               return rc;
+       }
+       ref->IrpContext = IrpContext;
+       return 0;
+}
+
+int ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref)
+{
+       int ret;
+       sector_t orig_file_acl = ref->inode_ref->Inode.i_file_acl;
+       ret = ext4_xattr_write_to_disk(ref);
+       if (ref->IsOnDiskInodeDirty) {
+               ASSERT(ref->fs->InodeSize > EXT4_GOOD_OLD_INODE_SIZE);
+
+               /* As we may do block allocation in ext4_xattr_write_to_disk */
+               if (ret)
+                       ref->inode_ref->Inode.i_file_acl = orig_file_acl;
+
+               if (!ret) {
+                       ret = Ext2SaveInode(ref->IrpContext, ref->fs, &ref->inode_ref->Inode)
+                               ? 0 : -EIO;
+                       if (!ret) {
+                               ret = Ext2SaveInodeXattr(ref->IrpContext,
+                                               ref->fs,
+                                               &ref->inode_ref->Inode,
+                                               ref->OnDiskInode)
+                                       ? 0 : -EIO;
+                       }
+               }
+               ref->IsOnDiskInodeDirty = FALSE;
+       }
+       if (ref->block_loaded) {
+               if (!ret)
+                       extents_brelse(ref->block_bh);
+               else
+                       extents_bforget(ref->block_bh);
+
+               ref->block_bh = NULL;
+               ref->block_loaded = FALSE;
+       }
+       ext4_xattr_purge_items(ref);
+       Ext2DestroyInode(ref->fs, ref->OnDiskInode);
+       ref->OnDiskInode = NULL;
+       ref->inode_ref = NULL;
+       ref->fs = NULL;
+       return ret;
+}
+
+struct xattr_prefix {
+       const char *prefix;
+       __u8 name_index;
+};
+
+static const struct xattr_prefix prefix_tbl[] = {
+    {"user.", EXT4_XATTR_INDEX_USER},
+    {"system.posix_acl_access", EXT4_XATTR_INDEX_POSIX_ACL_ACCESS},
+    {"system.posix_acl_default", EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT},
+    {"trusted.", EXT4_XATTR_INDEX_TRUSTED},
+    {"security.", EXT4_XATTR_INDEX_SECURITY},
+    {"system.", EXT4_XATTR_INDEX_SYSTEM},
+    {"system.richacl", EXT4_XATTR_INDEX_RICHACL},
+    {NULL, 0},
+};
+
+const char *ext4_extract_xattr_name(const char *full_name, size_t full_name_len,
+                             __u8 *name_index, size_t *name_len,
+                             BOOL *found)
+{
+       int i;
+       ASSERT(name_index);
+       ASSERT(found);
+
+       *found = FALSE;
+
+       if (!full_name_len) {
+               if (name_len)
+                       *name_len = 0;
+
+               return NULL;
+       }
+
+       for (i = 0; prefix_tbl[i].prefix; i++) {
+               size_t prefix_len = strlen(prefix_tbl[i].prefix);
+               if (full_name_len >= prefix_len &&
+                   !memcmp(full_name, prefix_tbl[i].prefix, prefix_len)) {
+                       BOOL require_name =
+                               prefix_tbl[i].prefix[prefix_len - 1] == '.';
+                       *name_index = prefix_tbl[i].name_index;
+                       if (name_len)
+                               *name_len = full_name_len - prefix_len;
+
+                       if (!(full_name_len - prefix_len) && require_name)
+                               return NULL;
+
+                       *found = TRUE;
+                       if (require_name)
+                               return full_name + prefix_len;
+
+                       return NULL;
+               }
+       }
+       if (name_len)
+               *name_len = 0;
+
+       return NULL;
+}
+
+const char *ext4_get_xattr_name_prefix(__u8 name_index,
+                                      size_t *ret_prefix_len)
+{
+       int i;
+
+       for (i = 0; prefix_tbl[i].prefix; i++) {
+               size_t prefix_len = strlen(prefix_tbl[i].prefix);
+               if (prefix_tbl[i].name_index == name_index) {
+                       if (ret_prefix_len)
+                               *ret_prefix_len = prefix_len;
+
+                       return prefix_tbl[i].prefix;
+               }
+       }
+       if (ret_prefix_len)
+               *ret_prefix_len = 0;
+
+       return NULL;
+}
index 70dc2be..ea62543 100644 (file)
@@ -93,6 +93,11 @@ Ext2FastIoCheckIfPossible (
             ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                    (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
 
+            /* do nothing if target fie was deleted */
+            if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
+                _SEH2_LEAVE;
+            }
+
             if (IsDirectory(Fcb)) {
                 _SEH2_LEAVE;
             }
index cfc016b..a9aeb89 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "ext2fs.h"
 #include <linux/ext4.h>
+#include "linux/ext4_xattr.h"
 
 /* GLOBALS ***************************************************************/
 
@@ -29,6 +30,15 @@ extern PEXT2_GLOBAL Ext2Global;
 #pragma alloc_text(PAGE, Ext2DeleteFile)
 #endif
 
+static int Ext2IterateAllEa(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item, BOOL is_last)
+{
+    PULONG EaSize = xattr_ref->iter_arg;
+    ULONG EaEntrySize = 4 + 1 + 1 + 2 + item->name_len + 1 + item->data_size;
+
+    *EaSize += EaEntrySize - 4;
+    return EXT4_XATTR_ITERATE_CONT;
+}
+
 NTSTATUS
 Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
 {
@@ -205,6 +215,7 @@ Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
 
         case FileEaInformation:
         {
+            struct ext4_xattr_ref xattr_ref;
             PFILE_EA_INFORMATION FileEaInformation;
 
             if (Length < sizeof(FILE_EA_INFORMATION)) {
@@ -213,10 +224,19 @@ Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
             }
 
             FileEaInformation = (PFILE_EA_INFORMATION) Buffer;
-
-            // Romfs doesn't have any extended attributes
             FileEaInformation->EaSize = 0;
 
+            Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
+            if (!NT_SUCCESS(Status))
+                _SEH2_LEAVE;
+
+            xattr_ref.iter_arg = &FileEaInformation->EaSize;
+            ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa);
+            ext4_fs_put_xattr_ref(&xattr_ref);
+
+            if (FileEaInformation->EaSize)
+                FileEaInformation->EaSize += 4;
+
             Irp->IoStatus.Information = sizeof(FILE_EA_INFORMATION);
             Status = STATUS_SUCCESS;
         }
@@ -1936,12 +1956,14 @@ Ext2DeleteFile(
         ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
         bFcbLockAcquired = TRUE;
 
-        if (!(Dcb = Mcb->Parent->Fcb)) {
-            Dcb = Ext2AllocateFcb(Vcb, Mcb->Parent);
+        /* Mcb->Parent could be NULL when working with layered file systems */
+        if (Mcb->Parent) {
+            Dcb = Mcb->Parent->Fcb;
+            if (!Dcb)
+                Dcb = Ext2AllocateFcb(Vcb, Mcb->Parent);
         }
-        if (Dcb) {
+        if (Dcb)
             Ext2ReferXcb(&Dcb->ReferenceCount);
-        }
 
         if (bFcbLockAcquired) {
             ExReleaseResourceLite(&Vcb->FcbLock);
index d57a3b1..c3e3dcd 100644 (file)
@@ -35,41 +35,6 @@ Ext2FlushCompletionRoutine (
     return STATUS_SUCCESS;
 }
 
-NTSTATUS
-Ext2FlushFiles(
-    IN PEXT2_IRP_CONTEXT    IrpContext,
-    IN PEXT2_VCB            Vcb,
-    IN BOOLEAN              bShutDown
-)
-{
-    IO_STATUS_BLOCK    IoStatus;
-
-    PEXT2_FCB       Fcb;
-    PLIST_ENTRY     ListEntry;
-
-    if (IsVcbReadOnly(Vcb)) {
-        return STATUS_SUCCESS;
-    }
-
-    IoStatus.Status = STATUS_SUCCESS;
-
-    DEBUG(DL_INF, ( "Flushing Files ...\n"));
-
-    // Flush all Fcbs in Vcb list queue.
-    for (ListEntry = Vcb->FcbList.Flink;
-            ListEntry != &Vcb->FcbList;
-            ListEntry = ListEntry->Flink ) {
-
-        Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next);
-        ExAcquireResourceExclusiveLite(
-            &Fcb->MainResource, TRUE);
-        IoStatus.Status = Ext2FlushFile(IrpContext, Fcb, NULL);
-        ExReleaseResourceLite(&Fcb->MainResource);
-    }
-
-    return IoStatus.Status;
-}
-
 NTSTATUS
 Ext2FlushVolume (
     IN PEXT2_IRP_CONTEXT    IrpContext,
@@ -77,26 +42,12 @@ Ext2FlushVolume (
     IN BOOLEAN              bShutDown
 )
 {
-    IO_STATUS_BLOCK    IoStatus;
-
     DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n"));
 
     ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
     ExReleaseResourceLite(&Vcb->PagingIoResource);
 
-    /* acquire gd lock to avoid gd/bh creation */
-    ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
-
-    /* discard buffer_headers for group_desc */
-    Ext2DropBH(Vcb);
-
-    /* do flushing */
-    CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
-
-    /* release gd lock */
-    ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
-
-    return IoStatus.Status;
+    return Ext2FlushVcb(Vcb);
 }
 
 NTSTATUS
@@ -106,7 +57,7 @@ Ext2FlushFile (
     IN PEXT2_CCB            Ccb
 )
 {
-    IO_STATUS_BLOCK     IoStatus;
+    IO_STATUS_BLOCK     IoStatus = {0};
 
     ASSERT(Fcb != NULL);
     ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
@@ -114,6 +65,12 @@ Ext2FlushFile (
 
     _SEH2_TRY {
 
+        /* do nothing if target fie was deleted */
+        if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
+            IoStatus.Status = STATUS_FILE_DELETED;
+            _SEH2_LEAVE;
+        }
+
         /* update timestamp and achieve attribute */
         if (Ccb != NULL) {
 
@@ -147,6 +104,41 @@ Ext2FlushFile (
     return IoStatus.Status;
 }
 
+NTSTATUS
+Ext2FlushFiles(
+    IN PEXT2_IRP_CONTEXT    IrpContext,
+    IN PEXT2_VCB            Vcb,
+    IN BOOLEAN              bShutDown
+)
+{
+    IO_STATUS_BLOCK    IoStatus;
+
+    PEXT2_FCB       Fcb;
+    PLIST_ENTRY     ListEntry;
+
+    if (IsVcbReadOnly(Vcb)) {
+        return STATUS_SUCCESS;
+    }
+
+    IoStatus.Status = STATUS_SUCCESS;
+
+    DEBUG(DL_INF, ( "Flushing Files ...\n"));
+
+    // Flush all Fcbs in Vcb list queue.
+    for (ListEntry = Vcb->FcbList.Flink;
+            ListEntry != &Vcb->FcbList;
+            ListEntry = ListEntry->Flink ) {
+
+        Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next);
+        ExAcquireResourceExclusiveLite(
+            &Fcb->MainResource, TRUE);
+        Ext2FlushFile(IrpContext, Fcb, NULL);
+        ExReleaseResourceLite(&Fcb->MainResource);
+    }
+
+    return IoStatus.Status;
+}
+
 
 NTSTATUS
 Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext)
index 731e018..0216528 100644 (file)
@@ -2130,6 +2130,11 @@ Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
         }
         INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
 
+#ifdef _PNP_POWER_
+        /* don't care about power management requests */
+        VolumeDeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
+#endif
+
         VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
         ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
 
index eb0dfc8..4e968de 100644 (file)
@@ -581,6 +581,11 @@ DriverEntry (
         goto errorout;
     }
 
+#ifdef _PNP_POWER_
+    DiskdevObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
+    CdromdevObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
+#endif
+
     /* initializing */
     Ext2Global->DiskdevObject  = DiskdevObject;
     Ext2Global->CdromdevObject = CdromdevObject;
@@ -604,6 +609,9 @@ DriverEntry (
     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]      = Ext2BuildRequest;
     DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL]        = Ext2BuildRequest;
 
+    DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = Ext2BuildRequest;
+    DriverObject->MajorFunction[IRP_MJ_SET_EA] = Ext2BuildRequest;
+
     DriverObject->MajorFunction[IRP_MJ_CLEANUP]             = Ext2BuildRequest;
 
 #if (_WIN32_WINNT >= 0x0500)
index f65e0b5..4fb73ff 100644 (file)
@@ -421,7 +421,7 @@ static void buffer_head_insert(struct block_device *bdev, struct buffer_head *bh
     rb_insert(&bdev->bd_bh_root, &bh->b_rb_node, buffer_head_blocknr_cmp);
 }
 
-static void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh)
+void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh)
 {
     rb_erase(&bh->b_rb_node, &bdev->bd_bh_root);
 }
@@ -469,6 +469,9 @@ get_block_bh_mdl(
     bh->b_blocknr = block;
     bh->b_size = size;
     bh->b_data = NULL;
+#ifdef __REACTOS__
+    InitializeListHead(&bh->b_link);
+#endif
 
 again:
 
@@ -476,11 +479,12 @@ again:
     offset.QuadPart <<= BLOCK_BITS;
 
     if (zero) {
+        /* PIN_EXCLUSIVE disabled, likely to deadlock with volume operations */
         if (!CcPreparePinWrite(Vcb->Volume,
                             &offset,
                             bh->b_size,
                             FALSE,
-                            PIN_WAIT | PIN_EXCLUSIVE,
+                            PIN_WAIT /* | PIN_EXCLUSIVE */,
                             &bcb,
                             &ptr)) {
             Ext2Sleep(100);
@@ -563,12 +567,14 @@ int submit_bh_mdl(int rw, struct buffer_head *bh)
 
         SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
         Offset.QuadPart = ((LONGLONG)bh->b_blocknr) << BLOCK_BITS;
+
+        /* PIN_EXCLUSIVE disabled, likely to deadlock with volume operations */
         if (CcPreparePinWrite(
                     Vcb->Volume,
                     &Offset,
                     BLOCK_SIZE,
                     FALSE,
-                    PIN_WAIT | PIN_EXCLUSIVE,
+                    PIN_WAIT /* | PIN_EXCLUSIVE */,
                     &Bcb,
                     &Buffer )) {
 #if 0
@@ -592,8 +598,6 @@ int submit_bh_mdl(int rw, struct buffer_head *bh)
         }
 
     } else {
-
-        DbgBreak();
     }
 
 errorout:
@@ -644,6 +648,9 @@ get_block_bh_pin(
     bh->b_blocknr = block;
     bh->b_size = size;
     bh->b_data = NULL;
+#ifdef __REACTOS__
+    InitializeListHead(&bh->b_link);
+#endif
 
 again:
 
@@ -692,11 +699,11 @@ again:
     tbh = buffer_head_search(bdev, block);
     if (tbh) {
         get_bh(tbh);
-        ExReleaseResourceLite(&bdev->bd_bh_lock);
         free_buffer_head(bh);
         bh = tbh;
         RemoveEntryList(&bh->b_link);
         InitializeListHead(&bh->b_link);
+        ExReleaseResourceLite(&bdev->bd_bh_lock);
         goto errorout;
     } else {
         buffer_head_insert(bdev, bh);
@@ -734,7 +741,6 @@ int submit_bh_pin(int rw, struct buffer_head *bh)
                             (ULONG)bh->b_blocknr,
                             (bh->b_size >> BLOCK_BITS));
     } else {
-        DbgBreak();
     }
 
 errorout:
@@ -803,13 +809,6 @@ void __brelse(struct buffer_head *bh)
         ll_rw_block(WRITE, 1, &bh);
     }
 
-    if (1 == atomic_read(&bh->b_count)) {
-    } else if (atomic_dec_and_test(&bh->b_count)) {
-        atomic_inc(&bh->b_count);
-    } else {
-        return;
-    }
-
     ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE);
     if (atomic_dec_and_test(&bh->b_count)) {
         ASSERT(0 == atomic_read(&bh->b_count));
@@ -817,8 +816,11 @@ void __brelse(struct buffer_head *bh)
         ExReleaseResourceLite(&bdev->bd_bh_lock);
         return;
     }
-    buffer_head_remove(bdev, bh);
     KeQuerySystemTime(&bh->b_ts_drop);
+#ifdef __REACTOS__
+    if (!IsListEmpty(&bh->b_link))
+#endif
+    RemoveEntryList(&bh->b_link);
     InsertTailList(&Vcb->bd.bd_bh_free, &bh->b_link);
     KeClearEvent(&Vcb->bd.bd_bh_notify);
     ExReleaseResourceLite(&bdev->bd_bh_lock);
@@ -924,6 +926,7 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned long size)
     return __getblk(bdev, block, size);
 }
 
+
 //
 // inode block mapping
 //
index 6678579..8915dfe 100644 (file)
@@ -207,7 +207,7 @@ Ext2UnlinkFcb(IN PEXT2_FCB Fcb)
     ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
     Mcb = Fcb->Mcb;
 
-    DEBUG(DL_ERR, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n",
+    DEBUG(DL_INF, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n",
                     Fcb, Mcb ? &Mcb->FullName : NULL));
 
     if ((Mcb != NULL) && 
@@ -2364,6 +2364,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
         ExInitializeResourceLite(&Vcb->MetaInode);
         ExInitializeResourceLite(&Vcb->MetaBlock);
         ExInitializeResourceLite(&Vcb->McbLock);
+        ExInitializeResourceLite(&Vcb->FcbLock);
         ExInitializeResourceLite(&Vcb->sbi.s_gd_lock);
 #ifndef _WIN2K_TARGET_
         ExInitializeFastMutex(&Vcb->Mutex);
@@ -2373,7 +2374,6 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
 
         /* initialize Fcb list head */
         InitializeListHead(&Vcb->FcbList);
-        ExInitializeResourceLite(&Vcb->FcbLock);
 
         /* initialize Mcb list head  */
         InitializeListHead(&(Vcb->McbList));
@@ -2401,7 +2401,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
 
         /* initialize inode lookaside list */
         ExInitializeNPagedLookasideList(&(Vcb->InodeLookasideList),
-                                        NULL, NULL, 0, sizeof(EXT2_INODE),
+                                        NULL, NULL, 0, Vcb->InodeSize,
                                         'SNIE', 0);
 
         InodeLookasideInitialized = TRUE;
@@ -2761,6 +2761,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
             }
 
             if (VcbResourceInitialized) {
+                ExDeleteResourceLite(&Vcb->FcbLock);
                 ExDeleteResourceLite(&Vcb->McbLock);
                 ExDeleteResourceLite(&Vcb->MetaInode);
                 ExDeleteResourceLite(&Vcb->MetaBlock);
@@ -2964,47 +2965,63 @@ Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
     PEXT2_MCB   Mcb = NULL;
     PLIST_ENTRY List = NULL;
     ULONG       i = 0;
+    LARGE_INTEGER   start, now;
 
     if (!ExAcquireResourceExclusiveLite(&Vcb->McbLock, Wait)) {
         return NULL;
     }
 
+    KeQuerySystemTime(&start);
+
     while (Number--) {
 
-        if (!IsListEmpty(&Vcb->McbList)) {
+        BOOLEAN     Skip = TRUE;
 
-            while (i++ < Vcb->NumOfMcb) {
+        if (IsListEmpty(&Vcb->McbList)) {
+            break;
+        }
 
-                List = RemoveHeadList(&Vcb->McbList);
-                Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link);
-                ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK));
+        while (i++ < Vcb->NumOfMcb) {
 
-                if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) &&
-                        Mcb->Refercount == 0 &&
-                        (Mcb->Child == NULL || IsMcbSymLink(Mcb))) {
+            KeQuerySystemTime(&now);
+            if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
+                break;
+            }
 
-                    Ext2RemoveMcb(Vcb, Mcb);
-                    ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
-                    Ext2DerefXcb(&Vcb->NumOfMcb);
+            List = RemoveHeadList(&Vcb->McbList);
+            Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link);
+            ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK));
 
-                    /* attach all Mcb into a chain*/
-                    if (Head) {
-                        ASSERT(Tail != NULL);
-                        Tail->Next = Mcb;
-                        Tail = Mcb;
-                    } else {
-                        Head = Tail = Mcb;
-                    }
-                    Tail->Next = NULL;
+            if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) &&
+                    Mcb->Refercount == 0 &&
+                    (Mcb->Child == NULL || IsMcbSymLink(Mcb))) {
 
-                } else {
+                Ext2RemoveMcb(Vcb, Mcb);
+                ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
+                Ext2DerefXcb(&Vcb->NumOfMcb);
 
-                    InsertTailList(&Vcb->McbList, &Mcb->Link);
-                    Mcb = NULL;
+                /* attach all Mcb into a chain*/
+                if (Head) {
+                    ASSERT(Tail != NULL);
+                    Tail->Next = Mcb;
+                    Tail = Mcb;
+                } else {
+                    Head = Tail = Mcb;
                 }
+                Tail->Next = NULL;
+                Skip = FALSE;
+
+            } else {
+
+                InsertTailList(&Vcb->McbList, &Mcb->Link);
+                Mcb = NULL;
             }
         }
+
+        if (Skip)
+            break;
     }
+
     ExReleaseResourceLite(&Vcb->McbLock);
 
     return Head;
@@ -3119,7 +3136,9 @@ Ext2McbReaperThread(
                     LastState = DidNothing = FALSE;
                 }
             }
-
+            if (DidNothing) {
+                KeClearEvent(&Reaper->Wait);
+            }
             if (GlobalAcquired) {
                 ExReleaseResourceLite(&Ext2Global->Resource);
                 GlobalAcquired = FALSE;
@@ -3145,15 +3164,21 @@ BOOLEAN
 Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
 {
     struct buffer_head *bh = NULL;
-    PLIST_ENTRY      next = NULL;
-    LARGE_INTEGER   now;
-    BOOLEAN         wake = FALSE;
+    PLIST_ENTRY         next = NULL;
+    LARGE_INTEGER       start, now;
+    BOOLEAN             wake = FALSE;
 
-    KeQuerySystemTime(&now);
+    KeQuerySystemTime(&start);
 
     ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
 
     while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
+
+        KeQuerySystemTime(&now);
+        if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
+            break;
+        }
+
         next = RemoveHeadList(&Vcb->bd.bd_bh_free);
         bh = CONTAINING_RECORD(next, struct buffer_head, b_link);
         if (atomic_read(&bh->b_count)) {
@@ -3166,6 +3191,7 @@ Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
             (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart ||
             (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) {
             InsertTailList(head, &bh->b_link);
+            buffer_head_remove(&Vcb->bd, bh);
         } else {
             InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link);
             break;
@@ -3240,12 +3266,15 @@ Ext2bhReaperThread(
                 Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
                 NonWait = Ext2QueryUnusedBH(Vcb, &List);
             }
+            DidNothing = IsListEmpty(&List);
+            if (DidNothing) {
+                KeClearEvent(&Reaper->Wait);
+            }
             if (GlobalAcquired) {
                 ExReleaseResourceLite(&Ext2Global->Resource);
                 GlobalAcquired = FALSE;
             }
 
-            DidNothing = IsListEmpty(&List);
             while (!IsListEmpty(&List)) {
                 struct buffer_head *bh;
                 Link = RemoveHeadList(&List);
@@ -3274,19 +3303,20 @@ Ext2QueryUnusedFcb(PEXT2_VCB Vcb, PLIST_ENTRY list)
 {
     PEXT2_FCB       Fcb;
     PLIST_ENTRY     next = NULL;
-    LARGE_INTEGER   now;
+    LARGE_INTEGER   start, now;
 
     ULONG           count = 0;
     ULONG           tries = 0;
     BOOLEAN         wake = FALSE;
     BOOLEAN         retry = TRUE;
 
-    KeQuerySystemTime(&now);
+    KeQuerySystemTime(&start);
 
     ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
 
 again:
 
+    KeQuerySystemTime(&now);
     while (!IsListEmpty(&Vcb->FcbList)) {
 
         next = RemoveHeadList(&Vcb->FcbList);
@@ -3312,6 +3342,10 @@ again:
         }
     }
 
+    if (start.QuadPart + 10*1000*1000 > now.QuadPart) {
+        retry = FALSE;
+    }
+
     if (retry) {
         if (++tries < (Vcb->FcbCount >> 4) )
             goto again;
@@ -3380,12 +3414,15 @@ Ext2FcbReaperThread(
                 Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
                 NonWait = Ext2QueryUnusedFcb(Vcb, &List);
             }
+            DidNothing = IsListEmpty(&List);
+            if (DidNothing) {
+                KeClearEvent(&Reaper->Wait);
+            }
             if (GlobalAcquired) {
                 ExReleaseResourceLite(&Ext2Global->Resource);
                 GlobalAcquired = FALSE;
             }
 
-            DidNothing = IsListEmpty(&List);
             while (!IsListEmpty(&List)) {
                 PEXT2_FCB  Fcb;
                 Link = RemoveHeadList(&List);
index 8840482..ce6aad3 100644 (file)
@@ -188,7 +188,7 @@ Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
                 (PFILE_FS_ATTRIBUTE_INFORMATION) Buffer;
             FsAttrInfo->FileSystemAttributes = FILE_SUPPORTS_HARD_LINKS |
                 FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
-                FILE_SUPPORTS_REPARSE_POINTS;
+                FILE_SUPPORTS_REPARSE_POINTS | FILE_SUPPORTS_EXTENDED_ATTRIBUTES;
             if (IsVcbReadOnly(Vcb)) {
                 FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
             }
index 6dec4c4..6f7d51a 100644 (file)
@@ -78,23 +78,24 @@ Ext2FloppyFlush(IN PVOID Parameter)
 
     if (FileObject) {
         ASSERT(Fcb == (PEXT2_FCB)FileObject->FsContext);
-
+        ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
         ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
         ExReleaseResourceLite(&Fcb->PagingIoResource);
 
         CcFlushCache(&(Fcb->SectionObject), NULL, 0, NULL);
+        ExReleaseResourceLite(&Fcb->MainResource);
 
         ObDereferenceObject(FileObject);
     }
 
     if (Vcb) {
+        ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
+
         ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
         ExReleaseResourceLite(&Vcb->PagingIoResource);
 
-        ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
-        Ext2DropBH(Vcb);
-        CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL);
-        ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+        Ext2FlushVcb(Vcb);
+        ExReleaseResourceLite(&Vcb->MainResource);
     }
 
     IoSetTopLevelIrp(NULL);
@@ -490,7 +491,7 @@ Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext)
                     }
 
                     Extent->Irp = NULL;
-                    Extent->Lba = DirtyLba;
+                    Extent->Lba = DirtyStart;
                     Extent->Offset = (ULONG)( DirtyStart + Length -
                                               RemainLength - DirtyLba );
                     ASSERT(Extent->Offset <= Length);
@@ -503,14 +504,17 @@ Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext)
                         RemainLength = 0;
                     } else {
                         Extent->Length = (ULONG)(DirtyLength + DirtyLba - DirtyStart);
+                        RemainLength = RemainLength - Extent->Length;
+/*
                         RemainLength =  (DirtyStart + RemainLength) -
                                         (DirtyLba + DirtyLength);
+*/
                         ASSERT(RemainLength <= (LONGLONG)Length);
                         ASSERT(Extent->Length <= Length);
                     }
 
                     ASSERT(Extent->Length >= SECTOR_SIZE);
-                    DirtyLba = DirtyStart + DirtyLength;
+                    DirtyLba = DirtyStart + Extent->Length;
 
                     if (List) {
                         List->Next = Extent;
index 14c6d60..c2ad019 100644 (file)
@@ -9,7 +9,7 @@ reactos/sdk/lib/fslib/btrfslib              # Synced to 1.0.1
 
 The following FSD are shared with: http://www.ext2fsd.com/
 
-reactos/drivers/filesystems/ext2            # Synced to 0.68, with b7657e5, e7c1142, 785943f
+reactos/drivers/filesystems/ext2            # Synced to 0.69
 
 The following FSD are shared with: http://www.acc.umu.se/~bosse/