Whamcloud - gitweb
libext2fs: strengthen i_extra_isize checks when reading/writing xattrs
[tools/e2fsprogs.git] / misc / create_inode.c
index 92086d2..a024d1c 100644 (file)
 #include <time.h>
 #include <unistd.h>
 #include <limits.h> /* for PATH_MAX */
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
 
 #include "create_inode.h"
+#include "nls-enable.h"
 
 #if __STDC_VERSION__ < 199901L
 # if __GNUC__ >= 2
@@ -103,6 +107,94 @@ static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t cwd,
        return retval;
 }
 
+static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino, const char *filename)
+{
+#ifdef HAVE_LLISTXATTR
+       errcode_t                       retval, close_retval;
+       struct ext2_inode               inode;
+       struct ext2_xattr_handle        *handle;
+       ssize_t                         size, value_size;
+       char                            *list;
+       int                             i;
+
+       size = llistxattr(filename, NULL, 0);
+       if (size == -1) {
+               com_err(__func__, errno, "llistxattr failed on %s", filename);
+               return errno;
+       } else if (size == 0) {
+               return 0;
+       }
+
+       retval = ext2fs_xattrs_open(fs, ino, &handle);
+       if (retval) {
+               if (retval == EXT2_ET_MISSING_EA_FEATURE)
+                       return 0;
+               com_err(__func__, retval, "while opening inode %u", ino);
+               return retval;
+       }
+
+       retval = ext2fs_get_mem(size, &list);
+       if (retval) {
+               com_err(__func__, retval, "whilst allocating memory");
+               goto out;
+       }
+
+       size = llistxattr(filename, list, size);
+       if (size == -1) {
+               com_err(__func__, errno, "llistxattr failed on %s", filename);
+               retval = errno;
+               goto out;
+        }
+
+       for (i = 0; i < size; i += strlen(&list[i]) + 1) {
+               const char *name = &list[i];
+               char *value;
+
+               value_size = getxattr(filename, name, NULL, 0);
+               if (value_size == -1) {
+                       com_err(__func__, errno, "getxattr failed on %s",
+                               filename);
+                       retval = errno;
+                       break;
+               }
+
+               retval = ext2fs_get_mem(value_size, &value);
+               if (retval) {
+                       com_err(__func__, retval, "whilst allocating memory");
+                       break;
+               }
+
+               value_size = getxattr(filename, name, value, value_size);
+               if (value_size == -1) {
+                       ext2fs_free_mem(&value);
+                       com_err(__func__, errno, "getxattr failed on %s",
+                               filename);
+                       retval = errno;
+                       break;
+               }
+
+               retval = ext2fs_xattr_set(handle, name, value, value_size);
+               ext2fs_free_mem(&value);
+               if (retval) {
+                       com_err(__func__, retval,
+                               "while writing xattr %u", ino);
+                       break;
+               }
+
+       }
+ out:
+       ext2fs_free_mem(&list);
+       close_retval = ext2fs_xattrs_close(&handle);
+       if (close_retval) {
+               com_err(__func__, retval, "while closing inode %u", ino);
+               retval = retval ? retval : close_retval;
+       }
+       return retval;
+#else /* HAVE_LLISTXATTR */
+       return 0;
+#endif  /* HAVE_LLISTXATTR */
+}
+
 /* Make a special files (block and character devices), fifo's, and sockets  */
 errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
                            struct stat *st)
@@ -197,8 +289,6 @@ errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
        char                    *cp;
        ext2_ino_t              parent_ino;
        errcode_t               retval;
-       struct ext2_inode       inode;
-       struct stat             st;
 
        cp = strrchr(name, '/');
        if (cp) {
@@ -233,9 +323,8 @@ errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
                            struct stat *st, ext2_ino_t root)
 {
        char                    *cp;
-       ext2_ino_t              parent_ino, ino;
+       ext2_ino_t              parent_ino;
        errcode_t               retval;
-       struct ext2_inode       inode;
 
 
        cp = strrchr(name, '/');
@@ -429,17 +518,13 @@ errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
                inode.i_flags |= EXT4_INLINE_DATA_FL;
        } else if (fs->super->s_feature_incompat &
                   EXT3_FEATURE_INCOMPAT_EXTENTS) {
-               int i;
-               struct ext3_extent_header *eh;
+               ext2_extent_handle_t handle;
 
-               eh = (struct ext3_extent_header *) &inode.i_block[0];
-               eh->eh_depth = 0;
-               eh->eh_entries = 0;
-               eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
-               i = (sizeof(inode.i_block) - sizeof(*eh)) /
-                       sizeof(struct ext3_extent);
-               eh->eh_max = ext2fs_cpu_to_le16(i);
-               inode.i_flags |= EXT4_EXTENTS_FL;
+               inode.i_flags &= ~EXT4_EXTENTS_FL;
+               retval = ext2fs_extent_open2(fs, newfile, &inode, &handle);
+               if (retval)
+                       return retval;
+               ext2fs_extent_free(handle);
        }
 
        retval = ext2fs_write_new_inode(fs, newfile, &inode);
@@ -620,6 +705,13 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
                        goto out;
                }
 
+               retval = set_inode_xattr(fs, ino, name);
+               if (retval) {
+                       com_err(__func__, retval,
+                               _("while setting xattrs for \"%s\""), name);
+                       goto out;
+               }
+
                /* Save the hardlink ino */
                if (save_inode) {
                        /*