Whamcloud - gitweb
Add library support for large (EA in inode) inodes. Make sure that garbage
authorTheodore Ts'o <tytso@mit.edu>
Wed, 26 Jan 2005 04:42:56 +0000 (23:42 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 26 Jan 2005 04:42:56 +0000 (23:42 -0500)
doesn't get written into the reserved portion when writing into filesystems
that have large inodes defined.

lib/ext2fs/ChangeLog
lib/ext2fs/ext2_fs.h
lib/ext2fs/ext2fs.h
lib/ext2fs/ext_attr.c
lib/ext2fs/inode.c
lib/ext2fs/swapfs.c

index c0dc827..451491e 100644 (file)
@@ -1,3 +1,25 @@
+2005-01-25  Theodore Ts'o  <tytso@mit.edu>
+
+       * ext2fs.h: Add definition of struct ext2_inode_large
+
+       * ext2_fs.h: Add new function prototypes
+
+       * ext_attr.c (ext2fs_read_ext_attr, ext2fs_write_ext_attr): The
+               ext2fs_swap_ext_attr() has been moved to swapfs.c, and
+               given a new argument, has_header.
+
+       * swapfs.c (ext2fs_swap_ext_attr): Moved from ext_attr.c, and
+               takes an argument which controls whether or not there is
+               an EA header which needs to be byteswaped.
+               (ext2fs_swap_inode_full): New function which byte-swaps
+               the EA in inode.
+
+       * inode.c (ext2fs_get_next_inode_full, ext2fs_read_inode_full,
+               ext2fs_write_inode_full): New functions, originally from
+               Alex Tomas, but which needed to be substantially fixed so
+               that the tests wouldn't cause major stack overwrite bugs
+               in byte-swapping is enabled.
+       
 2005-01-18  Theodore Ts'o  <tytso@mit.edu>
 
        * Makefile.in: Fix the kernel compile-time echo commands to be
index b182ef2..ff615c4 100644 (file)
@@ -304,6 +304,65 @@ struct ext2_inode {
        } osd2;                         /* OS dependent 2 */
 };
 
+/*
+ * Permanent part of an large inode on the disk
+ */
+struct ext2_inode_large {
+       __u16   i_mode;         /* File mode */
+       __u16   i_uid;          /* Low 16 bits of Owner Uid */
+       __u32   i_size;         /* Size in bytes */
+       __u32   i_atime;        /* Access time */
+       __u32   i_ctime;        /* Creation time */
+       __u32   i_mtime;        /* Modification time */
+       __u32   i_dtime;        /* Deletion Time */
+       __u16   i_gid;          /* Low 16 bits of Group Id */
+       __u16   i_links_count;  /* Links count */
+       __u32   i_blocks;       /* Blocks count */
+       __u32   i_flags;        /* File flags */
+       union {
+               struct {
+                       __u32  l_i_reserved1;
+               } linux1;
+               struct {
+                       __u32  h_i_translator;
+               } hurd1;
+               struct {
+                       __u32  m_i_reserved1;
+               } masix1;
+       } osd1;                         /* OS dependent 1 */
+       __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+       __u32   i_generation;   /* File version (for NFS) */
+       __u32   i_file_acl;     /* File ACL */
+       __u32   i_dir_acl;      /* Directory ACL */
+       __u32   i_faddr;        /* Fragment address */
+       union {
+               struct {
+                       __u8    l_i_frag;       /* Fragment number */
+                       __u8    l_i_fsize;      /* Fragment size */
+                       __u16   i_pad1;
+                       __u16   l_i_uid_high;   /* these 2 fields    */
+                       __u16   l_i_gid_high;   /* were reserved2[0] */
+                       __u32   l_i_reserved2;
+               } linux2;
+               struct {
+                       __u8    h_i_frag;       /* Fragment number */
+                       __u8    h_i_fsize;      /* Fragment size */
+                       __u16   h_i_mode_high;
+                       __u16   h_i_uid_high;
+                       __u16   h_i_gid_high;
+                       __u32   h_i_author;
+               } hurd2;
+               struct {
+                       __u8    m_i_frag;       /* Fragment number */
+                       __u8    m_i_fsize;      /* Fragment size */
+                       __u16   m_pad1;
+                       __u32   m_i_reserved2[2];
+               } masix2;
+       } osd2;                         /* OS dependent 2 */
+       __u16   i_extra_isize;
+       __u16   i_pad1;
+};
+
 #define i_size_high    i_dir_acl
 
 #if defined(__KERNEL__) || defined(__linux__)
index 1b7e1b0..a25c728 100644 (file)
@@ -698,7 +698,6 @@ extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest);
 extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
 
 /* ext_attr.c */
-void ext2fs_swap_ext_attr(ext2_filsys fs, char *to, char *from);
 extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
 extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
                                       void *buf);
@@ -787,6 +786,10 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
 
 /* inode.c */
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
+extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, 
+                                           ext2_ino_t *ino,
+                                           struct ext2_inode *inode, 
+                                           int bufsize);
 extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
                                  ext2_inode_scan *ret_scan);
 extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
@@ -803,8 +806,14 @@ extern void ext2fs_set_inode_callback
         void *done_group_data);
 extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
                                   int clear_flags);
+extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+                                       struct ext2_inode * inode, 
+                                       int bufsize);
 extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
                            struct ext2_inode * inode);
+extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+                                        struct ext2_inode * inode, 
+                                        int bufsize);
 extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
                            struct ext2_inode * inode);
 extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
@@ -909,8 +918,13 @@ extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
                                    ext2fs_generic_bitmap *dest);
 
 /* swapfs.c */
+extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, 
+                                int has_header);
 extern void ext2fs_swap_super(struct ext2_super_block * super);
 extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp);
+extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
+                                  struct ext2_inode_large *f, int hostorder,
+                                  int bufsize);
 extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
                              struct ext2_inode *f, int hostorder);
 
index 9aa092f..08211c3 100644 (file)
 
 #include "ext2fs.h"
 
-#ifdef EXT2FS_ENABLE_SWAPFS
-void ext2fs_swap_ext_attr(ext2_filsys fs, char *to, char *from)
-{
-       struct ext2_ext_attr_header *from_header =
-               (struct ext2_ext_attr_header *)from;
-       struct ext2_ext_attr_header *to_header =
-               (struct ext2_ext_attr_header *)to;
-       struct ext2_ext_attr_entry *from_entry, *to_entry;
-       char *from_end = (char *)from_header + fs->blocksize;
-       int n;
-
-       if (to_header != from_header)
-               memcpy(to_header, from_header, fs->blocksize);
-
-       to_header->h_magic    = ext2fs_swab32(from_header->h_magic);
-       to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
-       to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
-       for (n=0; n<4; n++)
-               to_header->h_reserved[n] =
-                       ext2fs_swab32(from_header->h_reserved[n]);
-       
-       from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
-       to_entry   = (struct ext2_ext_attr_entry *)(to_header+1);
-       while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
-               to_entry->e_value_offs  =       
-                       ext2fs_swab16(from_entry->e_value_offs);
-               to_entry->e_value_block =       
-                       ext2fs_swab32(from_entry->e_value_block);
-               to_entry->e_value_size  =       
-                       ext2fs_swab32(from_entry->e_value_size);
-               from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
-               to_entry   = EXT2_EXT_ATTR_NEXT(to_entry);
-       }
-}
-#endif
-
 errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
 {
        errcode_t       retval;
@@ -69,7 +33,7 @@ errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
 #ifdef EXT2FS_ENABLE_SWAPFS
        if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
                          EXT2_FLAG_SWAP_BYTES_READ)) != 0)
-               ext2fs_swap_ext_attr(fs, buf, buf);
+               ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
 #endif
        return 0;
 }
@@ -87,7 +51,7 @@ errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
                if (retval)
                        return retval;
                write_buf = buf;
-               ext2fs_swap_ext_attr(fs, buf, inbuf);
+               ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
        } else
 #endif
                write_buf = (char *) inbuf;
index d0de254..2517d67 100644 (file)
@@ -14,6 +14,9 @@
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
@@ -375,8 +378,8 @@ static inline int is_empty_scan(ext2_inode_scan scan)
 }
 #endif
 
-errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
-                               struct ext2_inode *inode)
+errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
+                                    struct ext2_inode *inode, int bufsize)
 {
        errcode_t       retval;
        int             extra_bytes = 0;
@@ -446,8 +449,10 @@ errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
 #ifdef EXT2FS_ENABLE_SWAPFS
                if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
                    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
-                       ext2fs_swap_inode(scan->fs, inode,
-                                (struct ext2_inode *) scan->temp_buffer, 0);
+                       ext2fs_swap_inode_full(scan->fs, 
+                               (struct ext2_inode_large *) inode,
+                               (struct ext2_inode_large *) scan->temp_buffer, 
+                               0, bufsize);
                else
 #endif
                        *inode = *((struct ext2_inode *) scan->temp_buffer);
@@ -458,11 +463,13 @@ errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
 #ifdef EXT2FS_ENABLE_SWAPFS
                if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
                    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
-                       ext2fs_swap_inode(scan->fs, inode,
-                                (struct ext2_inode *) scan->ptr, 0);
+                       ext2fs_swap_inode_full(scan->fs, 
+                               (struct ext2_inode_large *) inode,
+                               (struct ext2_inode_large *) scan->ptr,
+                               0, bufsize);
                else
 #endif
-                       *inode = *((struct ext2_inode *) scan->ptr);
+                       memcpy(inode, scan->ptr, bufsize);
                scan->ptr += scan->inode_size;
                scan->bytes_left -= scan->inode_size;
                if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
@@ -475,17 +482,23 @@ errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
        return retval;
 }
 
+errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
+                               struct ext2_inode *inode)
+{
+       return ext2fs_get_next_inode_full(scan, ino, inode,
+                                               sizeof(struct ext2_inode));
+}
+
 /*
  * Functions to read and write a single inode.
  */
-errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
-                            struct ext2_inode * inode)
+errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+                                struct ext2_inode * inode, int bufsize)
 {
        unsigned long   group, block, block_nr, offset;
        char            *ptr;
        errcode_t       retval;
-       int             clen, i, inodes_per_block;
-       unsigned int    length;
+       int             clen, i, inodes_per_block, length;
        io_channel      io;
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -503,10 +516,13 @@ errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
                        return retval;
        }
        /* Check to see if it's in the inode cache */
-       for (i=0; i < fs->icache->cache_size; i++) {
-               if (fs->icache->cache[i].ino == ino) {
-                       *inode = fs->icache->cache[i].inode;
-                       return 0;
+       if (bufsize == sizeof(struct ext2_inode)) {
+               /* only old good inode can be retrieve from the cache */
+               for (i=0; i < fs->icache->cache_size; i++) {
+                       if (fs->icache->cache[i].ino == ino) {
+                               *inode = fs->icache->cache[i].inode;
+                               return 0;
+                       }
                }
        }
        if ((ino == 0) || (ino > fs->super->s_inodes_count))
@@ -529,43 +545,41 @@ errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
                        block;
                io = fs->io;
        }
-       if (block_nr != fs->icache->buffer_blk) {
-               retval = io_channel_read_blk(io, block_nr, 1,
-                                            fs->icache->buffer);
-               if (retval)
-                       return retval;
-               fs->icache->buffer_blk = block_nr;
-       }
        offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
-       ptr = ((char *) fs->icache->buffer) + (unsigned) offset;
 
-       memset(inode, 0, sizeof(struct ext2_inode));
        length = EXT2_INODE_SIZE(fs->super);
-       if (length > sizeof(struct ext2_inode))
-               length = sizeof(struct ext2_inode);
-       
-       if ((offset + length) > (unsigned) EXT2_BLOCK_SIZE(fs->super)) {
-               clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
-               memcpy((char *) inode, ptr, clen);
-               length -= clen;
-               
-               retval = io_channel_read_blk(io, block_nr+1, 1,
-                                            fs->icache->buffer);
-               if (retval) {
-                       fs->icache->buffer_blk = 0;
-                       return retval;
+       if (bufsize < length)
+               length = bufsize;
+
+       ptr = (char *) inode;
+       while (length) {
+               clen = length;
+               if ((offset + length) > fs->blocksize)
+                       clen = fs->blocksize - offset;
+
+               if (block_nr != fs->icache->buffer_blk) {
+                       retval = io_channel_read_blk(io, block_nr, 1,
+                                                    fs->icache->buffer);
+                       if (retval)
+                               return retval;
+                       fs->icache->buffer_blk = block_nr;
                }
-               fs->icache->buffer_blk = block_nr+1;
-               
-               memcpy(((char *) inode) + clen,
-                      fs->icache->buffer, length);
-       } else
-               memcpy((char *) inode, ptr, length);
-       
+
+               memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
+                      clen);
+
+               offset = 0;
+               length -= clen;
+               ptr += clen;
+               block_nr++;
+       }
+
 #ifdef EXT2FS_ENABLE_SWAPFS
        if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
            (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
-               ext2fs_swap_inode(fs, inode, inode, 0);
+               ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode, 
+                                      (struct ext2_inode_large *) inode, 
+                                      0, length);
 #endif
 
        /* Update the inode cache */
@@ -577,15 +591,21 @@ errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
        return 0;
 }
 
-errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
-                            struct ext2_inode * inode)
+errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
+                           struct ext2_inode * inode)
+{
+       return ext2fs_read_inode_full(fs, ino, inode,
+                                       sizeof(struct ext2_inode));
+}
+
+errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+                                 struct ext2_inode * inode, int bufsize)
 {
        unsigned long group, block, block_nr, offset;
-       errcode_t       retval;
-       struct ext2_inode temp_inode;
+       errcode_t retval = 0;
+       struct ext2_inode_large temp_inode, *w_inode;
        char *ptr;
-       int clen, i;
-       unsigned int length;
+       int clen, i, length;
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -616,13 +636,27 @@ errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
        if ((ino == 0) || (ino > fs->super->s_inodes_count))
                return EXT2_ET_BAD_INODE_NUM;
 
+       length = bufsize;
+       if (length < EXT2_INODE_SIZE(fs->super))
+               length = EXT2_INODE_SIZE(fs->super);
+
+       if (length > (int) sizeof(struct ext2_inode_large)) {
+               w_inode = malloc(length);
+               if (!w_inode)
+                       return ENOMEM;
+       } else
+               w_inode = &temp_inode;
+       memset(w_inode, 0, length);
+
 #ifdef EXT2FS_ENABLE_SWAPFS
        if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
            (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
-               ext2fs_swap_inode(fs, &temp_inode, inode, 1);
+               ext2fs_swap_inode_full(fs, w_inode, 
+                                      (struct ext2_inode_large *) inode, 
+                                      1, bufsize);
        else
 #endif
-               memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
+               memcpy(w_inode, inode, bufsize);
        
        group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
        offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
@@ -631,54 +665,57 @@ errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
        if (!fs->group_desc[(unsigned) group].bg_inode_table)
                return EXT2_ET_MISSING_INODE_TABLE;
        block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
+
        offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
-       ptr = (char *) fs->icache->buffer + (unsigned) offset;
 
        length = EXT2_INODE_SIZE(fs->super);
-       clen = length;
-       if (length > sizeof(struct ext2_inode))
-               length = sizeof(struct ext2_inode);
-       
-       if (fs->icache->buffer_blk != block_nr) {
-               retval = io_channel_read_blk(fs->io, block_nr, 1,
-                                            fs->icache->buffer);
-               if (retval)
-                       return retval;
-               fs->icache->buffer_blk = block_nr;
-       }
-       
-       if ((offset + length) > (unsigned) EXT2_BLOCK_SIZE(fs->super)) {
-               clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
-               length -= clen;
-       } else {
-               length = 0;
-       }
-       memcpy(ptr, &temp_inode, clen);
-       retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer);
-       if (retval)
-               return retval;
+       if (length > bufsize)
+               length = bufsize;
 
-       if (length) {
-               retval = io_channel_read_blk(fs->io, ++block_nr, 1,
-                                            fs->icache->buffer);
-               if (retval) {
-                       fs->icache->buffer_blk = 0;
-                       return retval;
+       ptr = (char *) w_inode;
+
+       while (length) {
+               clen = length;
+               if ((offset + length) > fs->blocksize)
+                       clen = fs->blocksize - offset;
+
+               if (fs->icache->buffer_blk != block_nr) {
+                       retval = io_channel_read_blk(fs->io, block_nr, 1,
+                                                    fs->icache->buffer);
+                       if (retval)
+                               goto errout;
+                       fs->icache->buffer_blk = block_nr;
                }
-               fs->icache->buffer_blk = block_nr;
-               memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen,
-                      length);
 
-               retval = io_channel_write_blk(fs->io, block_nr, 1,
+       
+               memcpy((char *) fs->icache->buffer + (unsigned) offset, 
+                      ptr, clen);
+
+               retval = io_channel_write_blk(fs->io, block_nr, 1, 
                                              fs->icache->buffer);
                if (retval)
-                       return retval;
+                       goto errout;
+
+               offset = 0;
+               ptr += clen;
+               length -= clen;
+               block_nr++;
        }
-       
+               
        fs->flags |= EXT2_FLAG_CHANGED;
-       return 0;
+errout:
+       if (w_inode && w_inode != &temp_inode)
+               free(w_inode);
+       return retval;
 }
 
+errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
+                            struct ext2_inode *inode)
+{
+       return ext2fs_write_inode_full(fs, ino, inode,
+                                      sizeof(struct ext2_inode));
+}
 errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
 {
        struct ext2_inode       inode;
index f3c07e4..9081701 100644 (file)
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#include <string.h>
 #include <time.h>
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include <ext2fs/ext2_ext_attr.h>
 
 #ifdef EXT2FS_ENABLE_SWAPFS
 void ext2fs_swap_super(struct ext2_super_block * sb)
@@ -78,12 +80,53 @@ void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)
        gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
 }
 
-void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
-                      struct ext2_inode *f, int hostorder)
+void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
+{
+       struct ext2_ext_attr_header *from_header =
+               (struct ext2_ext_attr_header *)from;
+       struct ext2_ext_attr_header *to_header =
+               (struct ext2_ext_attr_header *)to;
+       struct ext2_ext_attr_entry *from_entry, *to_entry;
+       char *from_end = (char *)from_header + bufsize;
+       int n;
+
+       if (to_header != from_header)
+               memcpy(to_header, from_header, bufsize);
+
+       from_entry = (struct ext2_ext_attr_entry *)from_header;
+       to_entry   = (struct ext2_ext_attr_entry *)to_header;
+
+       if (has_header) {
+               to_header->h_magic    = ext2fs_swab32(from_header->h_magic);
+               to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
+               to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
+               for (n=0; n<4; n++)
+                       to_header->h_reserved[n] =
+                               ext2fs_swab32(from_header->h_reserved[n]);
+               from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
+               to_entry   = (struct ext2_ext_attr_entry *)(to_header+1);
+       }
+
+       while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
+               to_entry->e_value_offs  =       
+                       ext2fs_swab16(from_entry->e_value_offs);
+               to_entry->e_value_block =       
+                       ext2fs_swab32(from_entry->e_value_block);
+               to_entry->e_value_size  =       
+                       ext2fs_swab32(from_entry->e_value_size);
+               from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
+               to_entry   = EXT2_EXT_ATTR_NEXT(to_entry);
+       }
+}
+
+void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
+                           struct ext2_inode_large *f, int hostorder,
+                           int bufsize)
 {
        unsigned i;
        int islnk = 0;
-       
+       __u32 *eaf, *eat;
+
        if (hostorder && LINUX_S_ISLNK(f->i_mode))
                islnk = 1;
        t->i_mode = ext2fs_swab16(f->i_mode);
@@ -101,7 +144,7 @@ void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
        t->i_flags = ext2fs_swab32(f->i_flags);
        t->i_file_acl = ext2fs_swab32(f->i_file_acl);
        t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
-       if (!islnk || ext2fs_inode_data_blocks(fs, t)) {
+       if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) {
                for (i = 0; i < EXT2_N_BLOCKS; i++)
                        t->i_block[i] = ext2fs_swab32(f->i_block[i]);
        } else if (t != f) {
@@ -151,5 +194,44 @@ void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
                        ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
                break;
        }
+
+       if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
+               return; /* no i_extra_isize field */
+
+       t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
+       if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
+                               sizeof(struct ext2_inode)) {
+               /* this is error case: i_extra_size is too large */
+               return;
+       }
+
+       i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32);
+       if (bufsize < (int) i)
+               return; /* no space for EA magic */
+
+       eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
+                                       f->i_extra_isize);
+
+       if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC)
+               return; /* it seems no magic here */
+
+       eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
+                                       f->i_extra_isize);
+       *eat = ext2fs_swab32(*eaf);
+
+       /* convert EA(s) */
+       ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
+                            bufsize - sizeof(struct ext2_inode) -
+                            t->i_extra_isize - sizeof(__u32), 0);
+
 }
+
+void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
+                      struct ext2_inode *f, int hostorder)
+{
+       ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
+                               (struct ext2_inode_large *) f, hostorder,
+                               sizeof(struct ext2_inode));
+}
+
 #endif