]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Merge branch 'maint' into next
authorTheodore Ts'o <tytso@mit.edu>
Tue, 22 Aug 2017 16:19:30 +0000 (12:19 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 22 Aug 2017 16:19:30 +0000 (12:19 -0400)
138 files changed:
Android.bp [new file with mode: 0644]
Android.mk [deleted file]
MCONFIG.in
Makefile.in
configure
configure.ac
contrib/Android.bp [new file with mode: 0644]
contrib/Android.mk [deleted file]
contrib/android/Android.bp [new file with mode: 0644]
contrib/android/base_fs.c [new file with mode: 0644]
contrib/android/base_fs.h [new file with mode: 0644]
contrib/android/basefs_allocator.c [new file with mode: 0644]
contrib/android/basefs_allocator.h [new file with mode: 0644]
contrib/android/block_list.c [new file with mode: 0644]
contrib/android/block_list.h [new file with mode: 0644]
contrib/android/block_range.c [new file with mode: 0644]
contrib/android/block_range.h [new file with mode: 0644]
contrib/android/e2fsdroid.c [new file with mode: 0644]
contrib/android/ext2simg.c [new file with mode: 0644]
contrib/android/fsmap.c [new file with mode: 0644]
contrib/android/fsmap.h [new file with mode: 0644]
contrib/android/hashmap.c [new file with mode: 0644]
contrib/android/hashmap.h [new file with mode: 0644]
contrib/android/perms.c [new file with mode: 0644]
contrib/android/perms.h [new file with mode: 0644]
debugfs/Android.bp [new file with mode: 0644]
debugfs/Android.mk [deleted file]
debugfs/Makefile.in
debugfs/debugfs.c
debugfs/dump.c
debugfs/htree.c
debugfs/set_fields.c
debugfs/xattrs.c
e2fsck/Android.bp [new file with mode: 0644]
e2fsck/Android.mk [deleted file]
e2fsck/Makefile.in
e2fsck/e2fsck.c
e2fsck/e2fsck.h
e2fsck/ea_refcount.c
e2fsck/message.c
e2fsck/pass1.c
e2fsck/pass2.c
e2fsck/pass4.c
e2fsck/pass5.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/rehash.c
ext2ed/doc/ext2ed-design.sgml
ext2ed/doc/ext2fs-overview.sgml
ext2ed/ext2.descriptors
include/nonunix/linux/types.h
intl/Makefile.in
lib/Android.bp [new file with mode: 0644]
lib/Android.mk [deleted file]
lib/blkid/Android.bp [new file with mode: 0644]
lib/blkid/Android.mk [deleted file]
lib/blkid/Makefile.in
lib/blkid/devname.c
lib/config.h.in
lib/e2p/Android.bp [new file with mode: 0644]
lib/e2p/Android.mk [deleted file]
lib/e2p/Makefile.in
lib/et/Android.bp [new file with mode: 0644]
lib/et/Android.mk [deleted file]
lib/et/Makefile.in
lib/et/error_message.c
lib/ext2fs/Android.bp [new file with mode: 0644]
lib/ext2fs/Android.mk [deleted file]
lib/ext2fs/Makefile.in
lib/ext2fs/alloc.c
lib/ext2fs/bitops.h
lib/ext2fs/blkmap64_rb.c
lib/ext2fs/bmap.c
lib/ext2fs/csum.c
lib/ext2fs/ext2_ext_attr.h
lib/ext2fs/ext2_fs.h
lib/ext2fs/ext2_io.h
lib/ext2fs/ext2fs.h
lib/ext2fs/ext_attr.c
lib/ext2fs/flushb.c
lib/ext2fs/gen_bitmap.c
lib/ext2fs/inline_data.c
lib/ext2fs/jfs_compat.h
lib/ext2fs/namei.c
lib/ext2fs/sparse_io.c [new file with mode: 0644]
lib/ext2fs/swapfs.c
lib/ext2fs/symlink.c
lib/ext2fs/test_io.c
lib/ext2fs/unix_io.c
lib/ss/Android.bp [new file with mode: 0644]
lib/ss/Android.mk [deleted file]
lib/ss/Makefile.in
lib/support/Android.bp [new file with mode: 0644]
lib/support/Android.mk [deleted file]
lib/support/Makefile.in
lib/uuid/Android.bp [new file with mode: 0644]
lib/uuid/Android.mk [deleted file]
lib/uuid/Makefile.in
misc/Android.bp [new file with mode: 0644]
misc/Android.mk [deleted file]
misc/Makefile.in
misc/create_inode.c
misc/create_inode.h
misc/e2freefrag.c
misc/fsmap.h [new file with mode: 0644]
misc/fuse2fs.c
misc/mke2fs.c
misc/tune2fs.c
po/Makefile.in.in
po/at-expand.pl
resize/Android.bp [new file with mode: 0644]
resize/Android.mk [deleted file]
resize/Makefile.in
resize/resize2fs.c
tests/Makefile.in
tests/d_fallocate_blkmap/expect
tests/d_inline_dump/expect
tests/d_special_files/expect
tests/f_badcluster/expect
tests/f_convert_bmap/expect.1
tests/f_convert_bmap_and_extent/expect.1
tests/f_convert_bmap_sparse/expect.1
tests/f_create_symlinks/expect
tests/f_ea_inode/expect.1 [new file with mode: 0644]
tests/f_ea_inode/expect.2 [new file with mode: 0644]
tests/f_ea_inode/image.gz [new file with mode: 0644]
tests/f_large_dir/expect [new file with mode: 0644]
tests/f_large_dir/is_slow_test [new file with mode: 0644]
tests/f_large_dir/name [new file with mode: 0644]
tests/f_large_dir/script [new file with mode: 0644]
tests/f_mmp/is_slow_test [new file with mode: 0644]
tests/f_mmp_garbage/is_slow_test [new file with mode: 0644]
tests/f_recnect_bad/expect.1
tests/r_64bit_big_expand/is_slow_test [new file with mode: 0644]
tests/r_ext4_big_expand/is_slow_test [new file with mode: 0644]
tests/test_one.in
util/android_config.h
util/gen-android-files

diff --git a/Android.bp b/Android.bp
new file mode 100644 (file)
index 0000000..a095aea
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2017 The Android Open Source Project
+
+subdirs = [
+    "contrib",
+    "debugfs",
+    "e2fsck",
+    "lib",
+    "misc",
+    "resize",
+]
diff --git a/Android.mk b/Android.mk
deleted file mode 100644 (file)
index 5053e7d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
index e82963d238319f67c9d515259cc3294e0159c8d5..22b74eba44152f37a864f16e36dc390656c7a554 100644 (file)
@@ -4,6 +4,8 @@ all::
 
 check::
 
+fullcheck::
+
 SHELL = /bin/sh
 
 COMPRESS_EXT = gz bz2 bz Z
index 7da9ad7df16f709e59a9214b919155934c7407ea..37b60692f68f9ef3935cfdfea07d335082ab6698 100644 (file)
@@ -78,8 +78,9 @@ coverage.txt: coverage.txt-recursive
 
 check-recursive: all
 
-TAGS clean-recursive distclean-recursive depend-recursive check-recursive \
-  mostlyclean-recursive realclean-recursive coverage.txt-recursive:
+TAGS clean-recursive distclean-recursive depend-recursive fullcheck-recursive \
+  check-recursive mostlyclean-recursive realclean-recursive \
+  coverage.txt-recursive:
        @for subdir in $(SUBDIRS); do \
          if test -d $$subdir ; then \
            target=`echo $@|$(SED) 's/-recursive//'`; \
@@ -151,3 +152,4 @@ realclean-local: distclean-local
 
 check::        all check-recursive
 
+fullcheck:: all fullcheck-recursive
index 5318e2f49df447740785538691f8110fb15b6944..fc38dbed1e3a1ccdd5d62699f8fd12007d9a42b0 100755 (executable)
--- a/configure
+++ b/configure
@@ -12368,7 +12368,7 @@ fi
 done
 
 fi
-for ac_header in       dirent.h        errno.h         execinfo.h      getopt.h        malloc.h        mntent.h        paths.h         semaphore.h     setjmp.h        signal.h        stdarg.h        stdint.h        stdlib.h        termios.h       termio.h        unistd.h        utime.h         attr/xattr.h    linux/falloc.h  linux/fd.h      linux/major.h   linux/loop.h    net/if_dl.h     netinet/in.h    sys/acl.h       sys/disklabel.h         sys/disk.h      sys/file.h      sys/ioctl.h     sys/key.h       sys/mkdev.h     sys/mman.h      sys/mount.h     sys/prctl.h     sys/resource.h  sys/select.h    sys/socket.h    sys/sockio.h    sys/stat.h      sys/syscall.h   sys/sysctl.h    sys/sysmacros.h         sys/time.h      sys/types.h     sys/un.h        sys/wait.h
+for ac_header in       dirent.h        errno.h         execinfo.h      getopt.h        malloc.h        mntent.h        paths.h         semaphore.h     setjmp.h        signal.h        stdarg.h        stdint.h        stdlib.h        termios.h       termio.h        unistd.h        utime.h         attr/xattr.h    linux/falloc.h  linux/fd.h      linux/fsmap.h   linux/major.h   linux/loop.h    linux/types.h   net/if_dl.h     netinet/in.h    sys/acl.h       sys/disklabel.h         sys/disk.h      sys/file.h      sys/ioctl.h     sys/key.h       sys/mkdev.h     sys/mman.h      sys/mount.h     sys/prctl.h     sys/resource.h  sys/select.h    sys/socket.h    sys/sockio.h    sys/stat.h      sys/syscall.h   sys/sysctl.h    sys/sysmacros.h         sys/time.h      sys/types.h     sys/un.h        sys/wait.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -13073,7 +13073,7 @@ fi
 if test -n "$DLOPEN_LIB" ; then
    ac_cv_func_dlopen=yes
 fi
-for ac_func in         __secure_getenv         add_key         backtrace       blkid_probe_get_topology        blkid_probe_enable_partitions   chflags         dlopen  fadvise64       fallocate       fallocate64     fchown  fdatasync       fstat64         ftruncate64     futimes         getcwd  getdtablesize   getmntinfo      getpwuid_r      getrlimit       getrusage       jrand48         keyctl  llistxattr      llseek  lseek64         mallinfo        mbstowcs        memalign        mempcpy         mmap    msync   nanosleep       open64  pathconf        posix_fadvise   posix_fadvise64         posix_memalign  prctl   pread   pwrite  pread64         pwrite64        secure_getenv   setmntent       setresgid       setresuid       snprintf        srandom         stpcpy  strcasecmp      strdup  strnlen         strptime        strtoull        sync_file_range         sysconf         usleep  utime   utimes  valloc
+for ac_func in         __secure_getenv         add_key         backtrace       blkid_probe_get_topology        blkid_probe_enable_partitions   chflags         dlopen  fadvise64       fallocate       fallocate64     fchown  fcntl   fdatasync       fstat64         fsync   ftruncate64     futimes         getcwd  getdtablesize   getmntinfo      getpwuid_r      getrlimit       getrusage       jrand48         keyctl  llistxattr      llseek  lseek64         mallinfo        mbstowcs        memalign        mempcpy         mmap    msync   nanosleep       open64  pathconf        posix_fadvise   posix_fadvise64         posix_memalign  prctl   pread   pwrite  pread64         pwrite64        secure_getenv   setmntent       setresgid       setresuid       snprintf        srandom         stpcpy  strcasecmp      strdup  strnlen         strptime        strtoull        sync_file_range         sysconf         usleep  utime   utimes  valloc
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
index 4ede01caa832039369fda6ec42422f8c3124919f..ee05c67066b8e1391acb07d9b7aef3eeafb703c5 100644 (file)
@@ -918,8 +918,10 @@ AC_CHECK_HEADERS(m4_flatten([
        attr/xattr.h
        linux/falloc.h
        linux/fd.h
+       linux/fsmap.h
        linux/major.h
        linux/loop.h
+       linux/types.h
        net/if_dl.h
        netinet/in.h
        sys/acl.h
@@ -1094,8 +1096,10 @@ AC_CHECK_FUNCS(m4_flatten([
        fallocate
        fallocate64
        fchown
+       fcntl
        fdatasync
        fstat64
+       fsync
        ftruncate64
        futimes
        getcwd
diff --git a/contrib/Android.bp b/contrib/Android.bp
new file mode 100644 (file)
index 0000000..c2d5cd9
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2017 The Android Open Source Project
+
+subdirs = ["android"]
+
+//##########################################################################
+// Build fsstress
+
+cc_binary {
+    name: "fsstress",
+    host_supported: true,
+
+    srcs: ["fsstress.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    system_shared_libs: ["libc"],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+//########################################################################
+// Build add_ext4_encrypt
+
+cc_binary {
+    name: "add_ext4_encrypt",
+    host_supported: true,
+
+    srcs: ["add_ext4_encrypt.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+    ],
+    system_shared_libs: ["libc"],
+}
diff --git a/contrib/Android.mk b/contrib/Android.mk
deleted file mode 100644 (file)
index f8d74c3..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-###########################################################################
-# Build fsstress
-#
-fsstress_src_files := \
-       fsstress.c
-
-fsstress_c_includes := 
-
-fsstress_cflags := -O2 -g -W -Wall
-
-fsstress_shared_libraries := 
-
-fsstress_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(fsstress_src_files)
-mke2fs_c_includesLOCAL_CFLAGS := $(fsstress_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(fsstress_system_shared_libraries)
-LOCAL_MODULE := fsstress
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(fsstress_src_files)
-LOCAL_CFLAGS := $(fsstress_cflags)
-LOCAL_MODULE := fsstress_host
-LOCAL_MODULE_STEM := fsstress
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_HOST_OS := linux
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build add_ext4_encrypt
-#
-include $(CLEAR_VARS)
-
-add_ext4_encrypt_src_files := \
-       add_ext4_encrypt.c
-
-add_ext4_encrypt_c_includes := \
-       external/e2fsprogs/lib
-
-add_ext4_encrypt_cflags := -O2 -g -W -Wall
-
-add_ext4_encrypt_shared_libraries := \
-       libext2fs \
-       libext2_com_err
-
-add_ext4_encrypt_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(add_ext4_encrypt_src_files)
-LOCAL_C_INCLUDES := $(add_ext4_encrypt_c_includes)
-LOCAL_CFLAGS := $(add_ext4_encrypt_cflags)
-LOCAL_SHARED_LIBRARIES := $(add_ext4_encrypt_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(add_ext4_encrypt_system_shared_libraries)
-LOCAL_MODULE := add_ext4_encrypt
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(add_ext4_encrypt_src_files)
-LOCAL_C_INCLUDES := $(add_ext4_encrypt_c_includes)
-LOCAL_CFLAGS := $(add_ext4_encrypt_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(add_ext4_encrypt_shared_libraries))
-LOCAL_MODULE := add_ext4_encrypt_host
-LOCAL_MODULE_STEM := add_ext4_encrypt
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
diff --git a/contrib/android/Android.bp b/contrib/android/Android.bp
new file mode 100644 (file)
index 0000000..afa335e
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2017 The Android Open Source Project
+
+//##########################################################################
+// Build e2fsdroid
+
+cc_binary {
+    name: "e2fsdroid",
+    host_supported: true,
+
+    srcs: [
+        "e2fsdroid.c",
+        "block_range.c",
+        "fsmap.c",
+        "block_list.c",
+        "base_fs.c",
+        "perms.c",
+        "basefs_allocator.c",
+        "hashmap.c",
+    ],
+    cflags: ["-W", "-Wall"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libext2_misc",
+        "libcutils",
+        "libbase",
+        "libselinux",
+        "libcrypto",
+    ],
+}
+
+//##########################################################################
+// Build ext2simg
+
+cc_binary {
+    name: "ext2simg",
+    host_supported: true,
+
+    srcs: ["ext2simg.c"],
+    cflags: ["-W", "-Wall"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libsparse",
+    ],
+
+    target: {
+        host: {
+            shared_libs: ["libz-host"],
+        },
+        android: {
+            shared_libs: ["libz"],
+        },
+    },
+}
diff --git a/contrib/android/base_fs.c b/contrib/android/base_fs.c
new file mode 100644 (file)
index 0000000..2dcb5fe
--- /dev/null
@@ -0,0 +1,207 @@
+#include "base_fs.h"
+#include <stdio.h>
+
+#define BASE_FS_VERSION "Base EXT4 version 1.0"
+
+struct base_fs {
+       FILE *file;
+       const char *mountpoint;
+       struct basefs_entry entry;
+};
+
+static FILE *basefs_open(const char *file)
+{
+       char *line = NULL;
+       size_t len;
+       FILE *f = fopen(file, "r");
+       if (!f)
+               return NULL;
+
+       if (getline(&line, &len, f) == -1 || !line)
+               goto err_getline;
+
+       if (strncmp(line, BASE_FS_VERSION, strlen(BASE_FS_VERSION)))
+               goto err_header;
+
+       free(line);
+       return f;
+
+err_header:
+       free(line);
+err_getline:
+       fclose(f);
+       return NULL;
+}
+
+static struct basefs_entry *basefs_readline(FILE *f, const char *mountpoint,
+                                           int *err)
+{
+       char *line = NULL, *saveptr1, *saveptr2, *block_range, *block;
+       int offset;
+       size_t len;
+       struct basefs_entry *entry = NULL;
+       blk64_t range_start, range_end;
+
+       if (getline(&line, &len, f) == -1) {
+               if (feof(f))
+                       goto end;
+               goto err_getline;
+       }
+
+       entry = calloc(1, sizeof(*entry));
+       if (!entry)
+               goto err_alloc;
+
+       /*
+        * With BASEFS version 1.0, a typical line looks like this:
+        * /bin/mke2fs 5000-5004,8000,9000-9990
+        */
+       if (sscanf(line, "%ms%n", &entry->path, &offset) != 1)
+               goto err_sscanf;
+       len = strlen(mountpoint);
+       memmove(entry->path, entry->path + len, strlen(entry->path) - len + 1);
+
+       while (line[offset] == ' ')
+               ++offset;
+
+       block_range = strtok_r(line + offset, ",\n", &saveptr1);
+       while (block_range) {
+               block = strtok_r(block_range, "-", &saveptr2);
+               if (!block)
+                       break;
+               range_start = atoll(block);
+               block = strtok_r(NULL, "-", &saveptr2);
+               range_end = block ? atoll(block) : range_start;
+               add_blocks_to_range(&entry->head, &entry->tail, range_start,
+                                   range_end);
+               block_range = strtok_r(NULL, ",\n", &saveptr1);
+       }
+end:
+       *err = 0;
+       free(line);
+       return entry;
+
+err_sscanf:
+       free(entry);
+err_alloc:
+       free(line);
+err_getline:
+       *err = 1;
+       return NULL;
+}
+
+static void free_base_fs_entry(void *e)
+{
+       struct basefs_entry *entry = e;
+       if (entry) {
+               free(entry->path);
+               free(entry);
+       }
+}
+
+struct hashmap *basefs_parse(const char *file, const char *mountpoint)
+{
+       int err;
+       struct hashmap *entries = NULL;
+       struct basefs_entry *entry;
+       FILE *f = basefs_open(file);
+       if (!f)
+               return NULL;
+       entries = hashmap_create(djb2_hash, free_base_fs_entry, 1024);
+       if (!entries)
+               goto end;
+
+       while ((entry = basefs_readline(f, mountpoint, &err)))
+               hashmap_add(entries, entry, entry->path);
+
+       if (err) {
+               fclose(f);
+               hashmap_free(entries);
+               return NULL;
+       }
+end:
+       fclose(f);
+       return entries;
+}
+
+static void *init(const char *file, const char *mountpoint)
+{
+       struct base_fs *params = malloc(sizeof(*params));
+
+       if (!params)
+               return NULL;
+       params->mountpoint = mountpoint;
+       params->file = fopen(file, "w+");
+       if (!params->file) {
+               free(params);
+               return NULL;
+       }
+       if (fwrite(BASE_FS_VERSION"\n", 1, strlen(BASE_FS_VERSION"\n"),
+                  params->file) != strlen(BASE_FS_VERSION"\n")) {
+               fclose(params->file);
+               free(params);
+               return NULL;
+       }
+       return params;
+}
+
+static int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
+                         struct ext2_inode *inode, void *data)
+{
+       struct base_fs *params = data;
+
+       params->entry.head = params->entry.tail = NULL;
+       params->entry.path = LINUX_S_ISREG(inode->i_mode) ? path : NULL;
+       return 0;
+}
+
+static int add_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t blocknr,
+                    int metadata, void *data)
+{
+       struct base_fs *params = data;
+
+       if (params->entry.path && !metadata)
+               add_blocks_to_range(&params->entry.head, &params->entry.tail,
+                                   blocknr, blocknr);
+       return 0;
+}
+
+static int inline_data(void *inline_data EXT2FS_ATTR((unused)),
+                      void *data EXT2FS_ATTR((unused)))
+{
+       return 0;
+}
+
+static int end_new_file(void *data)
+{
+       struct base_fs *params = data;
+
+       if (!params->entry.path)
+               return 0;
+       if (fprintf(params->file, "%s%s ", params->mountpoint,
+                   params->entry.path) < 0
+           || write_block_ranges(params->file, params->entry.head, ",")
+           || fwrite("\n", 1, 1, params->file) != 1)
+               return -1;
+
+       delete_block_ranges(params->entry.head);
+       return 0;
+}
+
+static int cleanup(void *data)
+{
+       struct base_fs *params = data;
+
+       fclose(params->file);
+       free(params);
+       return 0;
+}
+
+struct fsmap_format base_fs_format = {
+       .init = init,
+       .start_new_file = start_new_file,
+       .add_block = add_block,
+       .inline_data = inline_data,
+       .end_new_file = end_new_file,
+       .cleanup = cleanup,
+};
diff --git a/contrib/android/base_fs.h b/contrib/android/base_fs.h
new file mode 100644 (file)
index 0000000..94bae29
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef BASE_FS_H
+# define BASE_FS_H
+
+# include "fsmap.h"
+# include "hashmap.h"
+# include "block_range.h"
+
+struct basefs_entry {
+       char *path;
+       struct block_range *head;
+       struct block_range *tail;
+};
+
+extern struct fsmap_format base_fs_format;
+
+struct hashmap *basefs_parse(const char *file, const char *mountpoint);
+
+#endif /* !BASE_FS_H */
diff --git a/contrib/android/basefs_allocator.c b/contrib/android/basefs_allocator.c
new file mode 100644 (file)
index 0000000..3d014a2
--- /dev/null
@@ -0,0 +1,147 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "basefs_allocator.h"
+#include "block_range.h"
+#include "hashmap.h"
+#include "base_fs.h"
+
+struct base_fs_allocator {
+       struct hashmap *entries;
+       struct basefs_entry *cur_entry;
+};
+
+static errcode_t basefs_block_allocator(ext2_filsys, blk64_t, blk64_t *,
+                                       struct blk_alloc_ctx *ctx);
+
+static void fs_free_blocks_range(ext2_filsys fs, struct block_range *blocks)
+{
+       while (blocks) {
+               ext2fs_unmark_block_bitmap_range2(fs->block_map, blocks->start,
+                       blocks->end - blocks->start + 1);
+               blocks = blocks->next;
+       }
+}
+
+static void fs_reserve_blocks_range(ext2_filsys fs, struct block_range *blocks)
+{
+       while (blocks) {
+               ext2fs_mark_block_bitmap_range2(fs->block_map,
+                       blocks->start, blocks->end - blocks->start + 1);
+               blocks = blocks->next;
+       }
+}
+
+errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
+                            const char *mountpoint)
+{
+       errcode_t retval;
+       struct basefs_entry *e;
+       struct hashmap_entry *it = NULL;
+       struct base_fs_allocator *allocator;
+       struct hashmap *entries = basefs_parse(file, mountpoint);
+       if (!entries)
+               return -1;
+
+       allocator = malloc(sizeof(*allocator));
+       if (!allocator)
+               goto err_alloc;
+
+       retval = ext2fs_read_bitmaps(fs);
+       if (retval)
+               goto err_bitmap;
+       while ((e = hashmap_iter_in_order(entries, &it)))
+               fs_reserve_blocks_range(fs, e->head);
+
+       allocator->cur_entry = NULL;
+       allocator->entries = entries;
+
+       /* Overhide the default allocator */
+       fs->get_alloc_block2 = basefs_block_allocator;
+       fs->priv_data = allocator;
+
+       return 0;
+
+err_bitmap:
+       free(allocator);
+err_alloc:
+       hashmap_free(entries);
+       return EXIT_FAILURE;
+}
+
+static errcode_t basefs_block_allocator(ext2_filsys fs, blk64_t goal,
+                                       blk64_t *ret, struct blk_alloc_ctx *ctx)
+{
+       errcode_t retval;
+       struct block_range *next_range;
+       struct base_fs_allocator *allocator = fs->priv_data;
+       struct basefs_entry *e = allocator->cur_entry;
+
+       /* Try to get a block from the base_fs */
+       if (e && e->head && ctx && (ctx->flags & BLOCK_ALLOC_DATA)) {
+               *ret = e->head->start;
+               e->head->start += 1;
+               if (e->head->start > e->head->end) {
+                       next_range = e->head->next;
+                       free(e->head);
+                       e->head = next_range;
+               }
+       } else { /* Allocate a new block */
+               retval = ext2fs_new_block2(fs, goal, fs->block_map, ret);
+               if (retval)
+                       return retval;
+               ext2fs_mark_block_bitmap2(fs->block_map, *ret);
+       }
+       return 0;
+}
+
+void base_fs_alloc_cleanup(ext2_filsys fs)
+{
+       struct basefs_entry *e;
+       struct hashmap_entry *it = NULL;
+       struct base_fs_allocator *allocator = fs->priv_data;
+
+       while ((e = hashmap_iter_in_order(allocator->entries, &it))) {
+               fs_free_blocks_range(fs, e->head);
+               delete_block_ranges(e->head);
+               e->head = e->tail = NULL;
+       }
+
+       fs->priv_data = NULL;
+       fs->get_alloc_block2 = NULL;
+       hashmap_free(allocator->entries);
+       free(allocator);
+}
+
+errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
+       const char *name EXT2FS_ATTR((unused)),
+       ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
+       ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
+{
+       struct base_fs_allocator *allocator = fs->priv_data;
+
+       if (mode != S_IFREG)
+               return 0;
+
+       if (allocator)
+               allocator->cur_entry = hashmap_lookup(allocator->entries,
+                                                     target_path);
+       return 0;
+}
+
+errcode_t base_fs_alloc_unset_target(ext2_filsys fs,
+        const char *target_path EXT2FS_ATTR((unused)),
+       const char *name EXT2FS_ATTR((unused)),
+       ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
+       ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
+{
+       struct base_fs_allocator *allocator = fs->priv_data;
+
+       if (!allocator || !allocator->cur_entry || mode != S_IFREG)
+               return 0;
+
+       fs_free_blocks_range(fs, allocator->cur_entry->head);
+       delete_block_ranges(allocator->cur_entry->head);
+       allocator->cur_entry->head = allocator->cur_entry->tail = NULL;
+       allocator->cur_entry = NULL;
+       return 0;
+}
diff --git a/contrib/android/basefs_allocator.h b/contrib/android/basefs_allocator.h
new file mode 100644 (file)
index 0000000..f1109cd
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef BASE_FS_ALLOCATOR_H
+# define BASE_FS_ALLOCATOR_H
+
+# include <time.h>
+# include <ext2fs/ext2fs.h>
+
+errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
+                            const char *mountpoint);
+void base_fs_alloc_cleanup(ext2_filsys fs);
+
+errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
+       const char *name, ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
+errcode_t base_fs_alloc_unset_target(ext2_filsys fs, const char *target_path,
+       const char *name, ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
+
+#endif /* !BASE_FS_ALLOCATOR_H */
diff --git a/contrib/android/block_list.c b/contrib/android/block_list.c
new file mode 100644 (file)
index 0000000..25dcc51
--- /dev/null
@@ -0,0 +1,94 @@
+#include "block_list.h"
+#include "block_range.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+struct block_list {
+       FILE *f;
+       const char *mountpoint;
+
+       struct {
+               const char *filename;
+               struct block_range *head;
+               struct block_range *tail;
+       } entry;
+};
+
+static void *init(const char *file, const char *mountpoint)
+{
+       struct block_list *params = malloc(sizeof(*params));
+
+       if (!params)
+               return NULL;
+       params->mountpoint = mountpoint;
+       params->f = fopen(file, "w+");
+       if (!params->f) {
+               free(params);
+               return NULL;
+       }
+       return params;
+}
+
+static int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
+                         struct ext2_inode *inode EXT2FS_ATTR((unused)),
+                         void *data)
+{
+       struct block_list *params = data;
+
+       params->entry.head = params->entry.tail = NULL;
+       params->entry.filename = LINUX_S_ISREG(inode->i_mode) ? path : NULL;
+       return 0;
+}
+
+static int add_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t blocknr,
+                    int metadata, void *data)
+{
+       struct block_list *params = data;
+
+       if (params->entry.filename && !metadata)
+               add_blocks_to_range(&params->entry.head, &params->entry.tail,
+                                   blocknr, blocknr);
+       return 0;
+}
+
+static int inline_data(void *inline_data EXT2FS_ATTR((unused)),
+                      void *data EXT2FS_ATTR((unused)))
+{
+       return 0;
+}
+
+static int end_new_file(void *data)
+{
+       struct block_list *params = data;
+
+       if (!params->entry.filename || !params->entry.head)
+               return 0;
+       if (fprintf(params->f, "%s%s ", params->mountpoint,
+                   params->entry.filename) < 0
+           || write_block_ranges(params->f, params->entry.head, " ")
+           || fwrite("\n", 1, 1, params->f) != 1)
+               return -1;
+
+       delete_block_ranges(params->entry.head);
+       return 0;
+}
+
+static int cleanup(void *data)
+{
+       struct block_list *params = data;
+
+       fclose(params->f);
+       free(params);
+       return 0;
+}
+
+struct fsmap_format block_list_format = {
+       .init = init,
+       .start_new_file = start_new_file,
+       .add_block = add_block,
+       .inline_data = inline_data,
+       .end_new_file = end_new_file,
+       .cleanup = cleanup,
+};
diff --git a/contrib/android/block_list.h b/contrib/android/block_list.h
new file mode 100644 (file)
index 0000000..47041e4
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef BLOCK_LIST_H
+# define BLOCK_LIST_H
+
+# include "fsmap.h"
+
+extern struct fsmap_format block_list_format;
+
+#endif /* !BLOCK_LIST_H */
diff --git a/contrib/android/block_range.c b/contrib/android/block_range.c
new file mode 100644 (file)
index 0000000..2f951c7
--- /dev/null
@@ -0,0 +1,64 @@
+#define _GNU_SOURCE
+
+#include "block_range.h"
+#include <stdio.h>
+
+struct block_range *new_block_range(blk64_t start, blk64_t end)
+{
+       struct block_range *range = malloc(sizeof(*range));
+       range->start = start;
+       range->end = end;
+       range->next = NULL;
+       return range;
+}
+
+void add_blocks_to_range(struct block_range **head, struct block_range **tail,
+                        blk64_t blk_start, blk64_t blk_end)
+{
+       if (*head == NULL)
+               *head = *tail = new_block_range(blk_start, blk_end);
+       else if ((*tail)->end + 1 == blk_start)
+               (*tail)->end += (blk_end - blk_start + 1);
+       else {
+               struct block_range *range = new_block_range(blk_start, blk_end);
+               (*tail)->next = range;
+               *tail = range;
+       }
+}
+
+void delete_block_ranges(struct block_range *head)
+{
+       struct block_range *tmp;
+
+       while (head) {
+               tmp = head->next;
+               free(head);
+               head = tmp;
+       }
+}
+
+int write_block_ranges(FILE *f, struct block_range *range,
+                                    char *sep)
+{
+       int len;
+       char *buf;
+
+       while (range) {
+               if (range->start == range->end)
+                       len = asprintf(&buf, "%llu%s", range->start, sep);
+               else
+                       len = asprintf(&buf, "%llu-%llu%s", range->start,
+                                      range->end, sep);
+               if (fwrite(buf, 1, len, f) != (size_t)len) {
+                       free(buf);
+                       return -1;
+               }
+               free(buf);
+               range = range->next;
+       }
+
+       len = strlen(sep);
+       if (fseek(f, -len, SEEK_CUR) == -len)
+               return -1;
+       return 0;
+}
diff --git a/contrib/android/block_range.h b/contrib/android/block_range.h
new file mode 100644 (file)
index 0000000..31e3c23
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef BLOCK_RANGE_H
+# define BLOCK_RANGE_H
+
+# include <sys/types.h>
+# include <ext2fs/ext2fs.h>
+
+struct block_range {
+       blk64_t start;
+       blk64_t end;
+       struct block_range *next;
+};
+
+void add_blocks_to_range(struct block_range **head, struct block_range **tail,
+                        blk64_t blk_start, blk64_t blk_end);
+void delete_block_ranges(struct block_range *head);
+int write_block_ranges(FILE *f, struct block_range *range, char *sep);
+
+#endif /* !BLOCK_RANGE_H */
diff --git a/contrib/android/e2fsdroid.c b/contrib/android/e2fsdroid.c
new file mode 100644 (file)
index 0000000..1ae133d
--- /dev/null
@@ -0,0 +1,194 @@
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <ext2fs/ext2fs.h>
+
+#include "perms.h"
+#include "base_fs.h"
+#include "block_list.h"
+#include "basefs_allocator.h"
+#include "create_inode.h"
+
+static char *prog_name = "e2fsdroid";
+static char *in_file;
+static char *block_list;
+static char *basefs_out;
+static char *basefs_in;
+static char *mountpoint = "";
+static time_t fixed_time = -1;
+static char *fs_config_file;
+static struct selinux_opt seopt_file[8];
+static int max_nr_opt = (int)sizeof(seopt_file) / sizeof(seopt_file[0]);
+static char *product_out;
+static char *src_dir;
+static int android_configure;
+static int android_sparse_file = 1;
+
+static void usage(int ret)
+{
+       fprintf(stderr, "%s [-B block_list] [-D basefs_out] [-T timestamp]\n"
+                       "\t[-C fs_config] [-S file_contexts] [-p product_out]\n"
+                       "\t[-a mountpoint] [-d basefs_in] [-f src_dir] [-e] image\n",
+                prog_name);
+       exit(ret);
+}
+
+static char *absolute_path(const char *file)
+{
+       char *ret;
+       char cwd[PATH_MAX];
+
+       if (file[0] != '/') {
+               getcwd(cwd, PATH_MAX);
+               ret = malloc(strlen(cwd) + 1 + strlen(file) + 1);
+               if (ret)
+                       sprintf(ret, "%s/%s", cwd, file);
+       } else
+               ret = strdup(file);
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int c;
+       char *p;
+       int flags = EXT2_FLAG_RW;
+       errcode_t retval;
+       io_manager io_mgr;
+       ext2_filsys fs = NULL;
+       struct fs_ops_callbacks fs_callbacks = { NULL, NULL };
+       char *token;
+       int nr_opt = 0;
+
+       add_error_table(&et_ext2_error_table);
+
+       while ((c = getopt (argc, argv, "T:C:S:p:a:D:d:B:f:e")) != EOF) {
+               switch (c) {
+               case 'T':
+                       fixed_time = strtoul(optarg, &p, 0);
+                       android_configure = 1;
+                       break;
+               case 'C':
+                       fs_config_file = absolute_path(optarg);
+                       android_configure = 1;
+                       break;
+               case 'S':
+                       token = strtok(optarg, ",");
+                       while (token) {
+                               if (nr_opt == max_nr_opt) {
+                                       fprintf(stderr, "Expected at most %d selinux opts\n",
+                                               max_nr_opt);
+                                       exit(EXIT_FAILURE);
+                               }
+                               seopt_file[nr_opt].type = SELABEL_OPT_PATH;
+                               seopt_file[nr_opt].value = absolute_path(token);
+                               nr_opt++;
+                               token = strtok(NULL, ",");
+                       }
+                       android_configure = 1;
+                       break;
+               case 'p':
+                       product_out = absolute_path(optarg);
+                       break;
+               case 'a':
+                       mountpoint = strdup(optarg);
+                       break;
+               case 'D':
+                       basefs_out = absolute_path(optarg);
+                       break;
+               case 'd':
+                       basefs_in = absolute_path(optarg);
+                       break;
+               case 'B':
+                       block_list = absolute_path(optarg);
+                       break;
+               case 'f':
+                       src_dir = absolute_path(optarg);
+                       break;
+               case 'e':
+                       android_sparse_file = 0;
+                       break;
+               default:
+                       usage(EXIT_FAILURE);
+               }
+       }
+       if (optind >= argc) {
+               fprintf(stderr, "Expected filename after options\n");
+               exit(EXIT_FAILURE);
+       }
+       in_file = strdup(argv[optind]);
+
+       io_mgr = android_sparse_file ? sparse_io_manager: unix_io_manager;
+       retval = ext2fs_open(in_file, flags, 0, 0, io_mgr, &fs);
+       if (retval) {
+               com_err(prog_name, retval, "while opening file %s\n", in_file);
+               return retval;
+       }
+
+       if (src_dir) {
+               ext2fs_read_bitmaps(fs);
+               if (basefs_in) {
+                       retval = base_fs_alloc_load(fs, basefs_in, mountpoint);
+                       if (retval) {
+                               com_err(prog_name, retval, "%s",
+                               "while reading base_fs file");
+                           exit(1);
+                       }
+                       fs_callbacks.create_new_inode =
+                               base_fs_alloc_set_target;
+                       fs_callbacks.end_create_new_inode =
+                               base_fs_alloc_unset_target;
+               }
+               retval = populate_fs2(fs, EXT2_ROOT_INO, src_dir,
+                                     EXT2_ROOT_INO, &fs_callbacks);
+               if (retval) {
+                       com_err(prog_name, retval, "%s",
+                       "while populating file system");
+                   exit(1);
+               }
+               if (basefs_in)
+                       base_fs_alloc_cleanup(fs);
+       }
+
+       if (android_configure) {
+               retval = android_configure_fs(fs, src_dir, product_out, mountpoint,
+                       seopt_file, nr_opt, fs_config_file, fixed_time);
+               if (retval) {
+                       com_err(prog_name, retval, "%s",
+                               "while configuring the file system");
+                       exit(1);
+               }
+       }
+
+       if (block_list) {
+               retval = fsmap_iter_filsys(fs, &block_list_format, block_list,
+                                          mountpoint);
+               if (retval) {
+                       com_err(prog_name, retval, "%s",
+                               "while creating the block_list");
+                       exit(1);
+               }
+       }
+
+       if (basefs_out) {
+               retval = fsmap_iter_filsys(fs, &base_fs_format,
+                                          basefs_out, mountpoint);
+               if (retval) {
+                       com_err(prog_name, retval, "%s",
+                               "while creating the basefs file");
+                       exit(1);
+               }
+       }
+
+       retval = ext2fs_close_free(&fs);
+       if (retval) {
+               com_err(prog_name, retval, "%s",
+                               "while writing superblocks");
+               exit(1);
+       }
+
+       remove_error_table(&et_ext2_error_table);
+       return 0;
+}
diff --git a/contrib/android/ext2simg.c b/contrib/android/ext2simg.c
new file mode 100644 (file)
index 0000000..fcefe1d
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ext2fs/ext2fs.h>
+#include <et/com_err.h>
+#include <sparse/sparse.h>
+
+struct {
+       int     crc;
+       int     sparse;
+       int     gzip;
+       char    *in_file;
+       char    *out_file;
+       bool    overwrite_input;
+} params = {
+       .crc        = 0,
+       .sparse     = 1,
+       .gzip       = 0,
+};
+
+#define ext2fs_fatal(Retval, Format, ...) \
+       do { \
+               com_err("error", Retval, Format, __VA_ARGS__); \
+               exit(EXIT_FAILURE); \
+       } while(0)
+
+#define sparse_fatal(Format) \
+       do { \
+               fprintf(stderr, "sparse: "Format); \
+               exit(EXIT_FAILURE); \
+       } while(0)
+
+static void usage(char *path)
+{
+       char *progname = basename(path);
+
+       fprintf(stderr, "%s [ options ] <image or block device> <output image>\n"
+                       "  -c include CRC block\n"
+                       "  -z gzip output\n"
+                       "  -S don't use sparse output format\n", progname);
+}
+
+static struct buf_item {
+       struct buf_item     *next;
+       void                *buf[0];
+} *buf_list;
+
+static void add_chunk(ext2_filsys fs, struct sparse_file *s, blk_t chunk_start, blk_t chunk_end)
+{
+       int retval;
+       unsigned int nb_blk = chunk_end - chunk_start;
+       size_t len = nb_blk * fs->blocksize;
+       int64_t offset = (int64_t)chunk_start * (int64_t)fs->blocksize;
+
+       if (params.overwrite_input == false) {
+               if (sparse_file_add_file(s, params.in_file, offset, len, chunk_start) < 0)
+                       sparse_fatal("adding data to the sparse file");
+       } else {
+               /*
+                * The input file will be overwritten, make a copy of
+                * the blocks
+                */
+               struct buf_item *bi = calloc(1, sizeof(struct buf_item) + len);
+               if (buf_list == NULL)
+                       buf_list = bi;
+               else {
+                       bi->next = buf_list;
+                       buf_list = bi;
+               }
+
+               retval = io_channel_read_blk64(fs->io, chunk_start, nb_blk, bi->buf);
+               if (retval < 0)
+                       ext2fs_fatal(retval, "reading block %u - %u", chunk_start, chunk_end);
+
+               if (sparse_file_add_data(s, bi->buf, len, chunk_start) < 0)
+                       sparse_fatal("adding data to the sparse file");
+       }
+}
+
+static void free_chunks(void)
+{
+       struct buf_item *bi;
+
+       while (buf_list) {
+               bi = buf_list->next;
+               free(buf_list);
+               buf_list = bi;
+       }
+}
+
+static struct sparse_file *ext_to_sparse(const char *in_file)
+{
+       errcode_t retval;
+       ext2_filsys fs;
+       struct sparse_file *s;
+       int64_t chunk_start = -1;
+       blk_t first_blk, last_blk, nb_blk, cur_blk;
+
+       retval = ext2fs_open(in_file, 0, 0, 0, unix_io_manager, &fs);
+       if (retval)
+               ext2fs_fatal(retval, "while reading %s", in_file);
+
+       retval = ext2fs_read_block_bitmap(fs);
+       if (retval)
+               ext2fs_fatal(retval, "while reading block bitmap of %s", in_file);
+
+       first_blk = ext2fs_get_block_bitmap_start2(fs->block_map);
+       last_blk = ext2fs_get_block_bitmap_end2(fs->block_map);
+       nb_blk = last_blk - first_blk + 1;
+
+       s = sparse_file_new(fs->blocksize, (uint64_t)fs->blocksize * (uint64_t)nb_blk);
+       if (!s)
+               sparse_fatal("creating sparse file");
+
+       /*
+        * The sparse format encodes the size of a chunk (and its header) in a
+        * 32-bit unsigned integer (UINT32_MAX)
+        * When writing the chunk, the library uses a single call to write().
+        * Linux's implementation of the 'write' syscall does not allow transfers
+        * larger than INT32_MAX (32-bit _and_ 64-bit systems).
+        * Make sure we do not create chunks larger than this limit.
+        */
+       int64_t max_blk_per_chunk = (INT32_MAX - 12) / fs->blocksize;
+
+       /* Iter on the blocks to merge contiguous chunk */
+       for (cur_blk = first_blk; cur_blk <= last_blk; ++cur_blk) {
+               if (ext2fs_test_block_bitmap2(fs->block_map, cur_blk)) {
+                       if (chunk_start == -1) {
+                               chunk_start = cur_blk;
+                       } else if (cur_blk - chunk_start + 1 == max_blk_per_chunk) {
+                               add_chunk(fs, s, chunk_start, cur_blk);
+                               chunk_start = -1;
+                       }
+               } else if (chunk_start != -1) {
+                       add_chunk(fs, s, chunk_start, cur_blk);
+                       chunk_start = -1;
+               }
+       }
+       if (chunk_start != -1)
+               add_chunk(fs, s, chunk_start, cur_blk - 1);
+
+       ext2fs_free(fs);
+       return s;
+}
+
+static bool same_file(const char *in, const char *out)
+{
+       struct stat st1, st2;
+
+       if (access(out, F_OK) == -1)
+               return false;
+
+       if (lstat(in, &st1) == -1)
+               ext2fs_fatal(errno, "stat %s\n", in);
+       if (lstat(out, &st2) == -1)
+               ext2fs_fatal(errno, "stat %s\n", out);
+       return st1.st_ino == st2.st_ino;
+}
+
+int main(int argc, char *argv[])
+{
+       int opt;
+       int out_fd;
+       errcode_t retval;
+       struct sparse_file *s;
+
+       while ((opt = getopt(argc, argv, "czS")) != -1) {
+               switch(opt) {
+               case 'c':
+                       params.crc = 1;
+                       break;
+               case 'z':
+                       params.gzip = 1;
+                       break;
+               case 'S':
+                       params.sparse = 0;
+                       break;
+               default:
+                       usage(argv[0]);
+                       exit(EXIT_FAILURE);
+               }
+       }
+       if (optind + 1 >= argc) {
+               usage(argv[0]);
+               exit(EXIT_FAILURE);
+       }
+       params.in_file = strdup(argv[optind++]);
+       params.out_file = strdup(argv[optind]);
+       params.overwrite_input = same_file(params.in_file, params.out_file);
+
+       s = ext_to_sparse(params.in_file);
+
+       out_fd = open(params.out_file, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+       if (out_fd == -1)
+               ext2fs_fatal(errno, "opening %s\n", params.out_file);
+       if (sparse_file_write(s, out_fd, params.gzip, params.sparse, params.crc) < 0)
+               sparse_fatal("writing sparse file");
+
+       sparse_file_destroy(s);
+
+       free(params.in_file);
+       free(params.out_file);
+       free_chunks();
+       close(out_fd);
+
+       return 0;
+}
diff --git a/contrib/android/fsmap.c b/contrib/android/fsmap.c
new file mode 100644 (file)
index 0000000..36adb7f
--- /dev/null
@@ -0,0 +1,119 @@
+#include "fsmap.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "support/nls-enable.h"
+
+struct walk_ext_priv_data {
+       char                    *path;
+       ext2_filsys             fs;
+       struct fsmap_format     *format;
+};
+
+static int walk_block(ext2_filsys fs  EXT2FS_ATTR((unused)), blk64_t *blocknr,
+                     e2_blkcnt_t blockcnt,
+                     blk64_t ref64_blk EXT2FS_ATTR((unused)),
+                     int ref_offset EXT2FS_ATTR((unused)),
+                     void *priv)
+{
+       struct walk_ext_priv_data *pdata = priv;
+       struct fsmap_format *format = pdata->format;
+
+       return format->add_block(fs, *blocknr, blockcnt < 0, format->private);
+}
+
+static errcode_t ino_iter_blocks(ext2_filsys fs, ext2_ino_t ino,
+                                struct walk_ext_priv_data *pdata)
+{
+       errcode_t retval;
+       struct ext2_inode inode;
+       struct fsmap_format *format = pdata->format;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               return retval;
+
+       if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
+               return format->inline_data(&(inode.i_block[0]),
+                                          format->private);
+
+       retval = ext2fs_block_iterate3(fs, ino, 0, NULL, walk_block, pdata);
+       if (retval)
+               com_err(__func__, retval, _("listing blocks of ino \"%u\""),
+                       ino);
+       return retval;
+}
+
+static int is_dir(ext2_filsys fs, ext2_ino_t ino)
+{
+       struct ext2_inode inode;
+
+       if (ext2fs_read_inode(fs, ino, &inode))
+               return 0;
+       return S_ISDIR(inode.i_mode);
+}
+
+static int walk_ext_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
+                       int flags EXT2FS_ATTR((unused)),
+                       struct ext2_dir_entry *de,
+                       int offset EXT2FS_ATTR((unused)),
+                       int blocksize EXT2FS_ATTR((unused)),
+                       char *buf EXT2FS_ATTR((unused)), void *priv_data)
+{
+       errcode_t retval;
+       struct ext2_inode inode;
+       char *filename, *cur_path, *name = de->name;
+       int name_len = de->name_len & 0xff;
+       struct walk_ext_priv_data *pdata = priv_data;
+       struct fsmap_format *format = pdata->format;
+
+       if (!strncmp(name, ".", name_len)
+           || !strncmp(name, "..", name_len)
+           || !strncmp(name, "lost+found", 10))
+               return 0;
+
+       if (asprintf(&filename, "%s/%.*s", pdata->path, name_len, name) < 0)
+               return -ENOMEM;
+
+       retval = ext2fs_read_inode(pdata->fs, de->inode, &inode);
+       if (retval) {
+               com_err(__func__, retval, _("reading ino \"%u\""), de->inode);
+               goto end;
+       }
+       format->start_new_file(filename, de->inode, &inode, format->private);
+       retval = ino_iter_blocks(pdata->fs, de->inode, pdata);
+       if (retval)
+               return retval;
+       format->end_new_file(format->private);
+
+       retval = 0;
+       if (is_dir(pdata->fs, de->inode)) {
+               cur_path = pdata->path;
+               pdata->path = filename;
+               retval = ext2fs_dir_iterate2(pdata->fs, de->inode, 0, NULL,
+                                   walk_ext_dir, pdata);
+               pdata->path = cur_path;
+       }
+
+end:
+       free(filename);
+       return retval;
+}
+
+errcode_t fsmap_iter_filsys(ext2_filsys fs, struct fsmap_format *format,
+                           const char *file, const char *mountpoint)
+{
+       struct walk_ext_priv_data pdata;
+       errcode_t retval;
+
+       format->private = format->init(file, mountpoint);
+       pdata.fs = fs;
+       pdata.path = "";
+       pdata.format = format;
+
+       retval = ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_ext_dir, &pdata);
+
+       format->cleanup(format->private);
+       return retval;
+}
diff --git a/contrib/android/fsmap.h b/contrib/android/fsmap.h
new file mode 100644 (file)
index 0000000..9f84a71
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef FSMAP_H
+# define FSMAP_H
+
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE // asprintf
+# endif
+# include <stdio.h>
+# include <stdint.h>
+# include <stdbool.h>
+# include <sys/types.h>
+# include <ext2fs/ext2fs.h>
+
+struct fsmap_format {
+       void* (* init)(const char *file, const char *mountpoint);
+       int   (* start_new_file)(char *path, ext2_ino_t ino,
+                                struct ext2_inode *inode, void *data);
+       int   (* add_block)(ext2_filsys fs, blk64_t blocknr, int metadata,
+                           void *data);
+       int   (* inline_data)(void *inline_data, void *data);
+       int   (* end_new_file)(void *data);
+       int   (* cleanup)(void *data);
+
+       void *private;
+};
+
+errcode_t fsmap_iter_filsys(ext2_filsys fs, struct fsmap_format *format,
+                           const char *file, const char *mountpoint);
+
+#endif /* !FSMAP_H */
diff --git a/contrib/android/hashmap.c b/contrib/android/hashmap.c
new file mode 100644 (file)
index 0000000..eee0071
--- /dev/null
@@ -0,0 +1,76 @@
+#include "hashmap.h"
+#include <string.h>
+
+uint32_t djb2_hash(const void *str)
+{
+       int c;
+       const char *s = str;
+       uint32_t hash = 5381;
+
+       while ((c = *s++))
+               hash = ((hash << 5) + hash) + c;
+       return hash;
+}
+
+struct hashmap *hashmap_create(uint32_t(*hash_fct)(const void*),
+                              void(*free_fct)(void*), size_t size)
+{
+       struct hashmap *h = calloc(sizeof(struct hashmap) +
+                                     sizeof(struct hashmap_entry) * size, 1);
+       h->size = size;
+       h->free = free_fct;
+       h->hash = hash_fct;
+       h->first = h->last = NULL;
+       return h;
+}
+
+void hashmap_add(struct hashmap *h, void *data, const void *key)
+{
+       uint32_t hash = h->hash(key) % h->size;
+       struct hashmap_entry *e = malloc(sizeof(*e));
+
+       e->data = data;
+       e->key = key;
+       e->next = h->entries[hash];
+       h->entries[hash] = e;
+
+       e->list_prev = NULL;
+       e->list_next = h->first;
+       if (h->first)
+               h->first->list_prev = e;
+       h->first = e;
+       if (!h->last)
+               h->last = e;
+}
+
+void *hashmap_lookup(struct hashmap *h, const void *key)
+{
+       struct hashmap_entry *iter;
+       uint32_t hash = h->hash(key) % h->size;
+
+       for (iter = h->entries[hash]; iter; iter = iter->next)
+               if (!strcmp(iter->key, key))
+                       return iter->data;
+       return NULL;
+}
+
+void *hashmap_iter_in_order(struct hashmap *h, struct hashmap_entry **it)
+{
+       *it = *it ? (*it)->list_next : h->first;
+       return *it ? (*it)->data : NULL;
+}
+
+void hashmap_free(struct hashmap *h)
+{
+       for (size_t i = 0; i < h->size; ++i) {
+               struct hashmap_entry *it = h->entries[i];
+               while (it) {
+                       struct hashmap_entry *tmp = it->next;
+                       if (h->free)
+                               h->free(it->data);
+                       free(it);
+                       it = tmp;
+               }
+       }
+       free(h);
+}
diff --git a/contrib/android/hashmap.h b/contrib/android/hashmap.h
new file mode 100644 (file)
index 0000000..70d0ed1
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef HASHMAP_H
+# define HASHMAP_H
+
+# include <stdlib.h>
+# include <stdint.h>
+
+struct hashmap {
+       uint32_t size;
+       uint32_t(*hash)(const void *key);
+       void(*free)(void*);
+       struct hashmap_entry *first;
+       struct hashmap_entry *last;
+       struct hashmap_entry {
+               void *data;
+               const void *key;
+               struct hashmap_entry *next;
+               struct hashmap_entry *list_next;
+               struct hashmap_entry *list_prev;
+       } *entries[0];
+};
+
+struct hashmap *hashmap_create(uint32_t(*hash_fct)(const void*),
+                              void(*free_fct)(void*), size_t size);
+void hashmap_add(struct hashmap *h, void *data, const void *key);
+void *hashmap_lookup(struct hashmap *h, const void *key);
+void *hashmap_iter_in_order(struct hashmap *h, struct hashmap_entry **it);
+void hashmap_del(struct hashmap *h, struct hashmap_entry *e);
+void hashmap_free(struct hashmap *h);
+
+uint32_t djb2_hash(const void *str);
+
+#endif /* !HASHMAP_H */
diff --git a/contrib/android/perms.c b/contrib/android/perms.c
new file mode 100644 (file)
index 0000000..08fb861
--- /dev/null
@@ -0,0 +1,319 @@
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE //asprintf
+#endif
+#include "perms.h"
+#include "support/nls-enable.h"
+#include <time.h>
+#include <sys/stat.h>
+
+#ifndef XATTR_SELINUX_SUFFIX
+# define XATTR_SELINUX_SUFFIX  "selinux"
+#endif
+#ifndef XATTR_CAPS_SUFFIX
+# define XATTR_CAPS_SUFFIX     "capability"
+#endif
+
+struct inode_params {
+       ext2_filsys fs;
+       char *path;
+       char *filename;
+       char *src_dir;
+       char *target_out;
+       char *mountpoint;
+       fs_config_f fs_config_func;
+       struct selabel_handle *sehnd;
+       time_t fixed_time;
+};
+
+static errcode_t ino_add_xattr(ext2_filsys fs, ext2_ino_t ino, const char *name,
+                              const void *value, int value_len)
+{
+       errcode_t retval, close_retval;
+       struct ext2_xattr_handle *xhandle;
+
+       retval = ext2fs_xattrs_open(fs, ino, &xhandle);
+       if (retval) {
+               com_err(__func__, retval, _("while opening inode %u"), ino);
+               return retval;
+       }
+       retval = ext2fs_xattrs_read(xhandle);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while reading xattrs of inode %u"), ino);
+               goto xattrs_close;
+       }
+       retval = ext2fs_xattr_set(xhandle, name, value, value_len);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while setting xattrs of inode %u"), ino);
+               goto xattrs_close;
+       }
+xattrs_close:
+       close_retval = ext2fs_xattrs_close(&xhandle);
+       if (close_retval) {
+               com_err(__func__, close_retval,
+                       _("while closing xattrs of inode %u"), ino);
+               return retval ? retval : close_retval;
+       }
+       return retval;
+}
+
+static errcode_t set_selinux_xattr(ext2_filsys fs, ext2_ino_t ino,
+                                  struct inode_params *params)
+{
+       errcode_t retval;
+       char *secontext = NULL;
+       struct ext2_inode inode;
+
+       if (params->sehnd == NULL)
+               return 0;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while reading inode %u"), ino);
+               return retval;
+       }
+
+       retval = selabel_lookup(params->sehnd, &secontext, params->filename,
+                               inode.i_mode);
+       if (retval < 0) {
+               com_err(__func__, retval,
+                       _("searching for label \"%s\""), params->filename);
+               exit(1);
+       }
+
+       retval = ino_add_xattr(fs, ino,  "security." XATTR_SELINUX_SUFFIX,
+                              secontext, strlen(secontext) + 1);
+
+       freecon(secontext);
+       return retval;
+}
+
+static errcode_t set_perms_and_caps(ext2_filsys fs, ext2_ino_t ino,
+                                   struct inode_params *params)
+{
+       errcode_t retval;
+       uint64_t capabilities = 0;
+       struct ext2_inode inode;
+       struct vfs_cap_data cap_data;
+       unsigned int uid = 0, gid = 0, imode = 0;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval) {
+               com_err(__func__, retval, _("while reading inode %u"), ino);
+               return retval;
+       }
+
+       /* Permissions */
+       if (params->fs_config_func != NULL) {
+               params->fs_config_func(params->filename, S_ISDIR(inode.i_mode),
+                                      params->target_out, &uid, &gid, &imode,
+                                      &capabilities);
+               inode.i_uid = uid & 0xffff;
+               inode.i_gid = gid & 0xffff;
+               inode.i_mode = (inode.i_mode & S_IFMT) | (imode & 0xffff);
+               retval = ext2fs_write_inode(fs, ino, &inode);
+               if (retval) {
+                       com_err(__func__, retval,
+                               _("while writting inode %u"), ino);
+                       return retval;
+               }
+       }
+
+       /* Capabilities */
+       if (!capabilities)
+               return 0;
+       memset(&cap_data, 0, sizeof(cap_data));
+       cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+       cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff);
+       cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
+       return ino_add_xattr(fs, ino,  "security." XATTR_CAPS_SUFFIX,
+                            &cap_data, sizeof(cap_data));
+}
+
+static errcode_t set_timestamp(ext2_filsys fs, ext2_ino_t ino,
+                              struct inode_params *params)
+{
+       errcode_t retval;
+       struct ext2_inode inode;
+       struct stat stat;
+       char *src_filename = NULL;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while reading inode %u"), ino);
+               return retval;
+       }
+
+       if (params->fixed_time == -1 && params->src_dir) {
+               /* replace mountpoint from filename with src_dir */
+               if (asprintf(&src_filename, "%s/%s", params->src_dir,
+                       params->filename + strlen(params->mountpoint)) < 0) {
+                       return -ENOMEM;
+               }
+               retval = lstat(src_filename, &stat);
+               if (retval < 0) {
+                       com_err(__func__, retval,
+                               _("while lstat file %s"), src_filename);
+                       goto end;
+               }
+               inode.i_atime = inode.i_ctime = inode.i_mtime = stat.st_mtime;
+       } else {
+               inode.i_atime = inode.i_ctime = inode.i_mtime = params->fixed_time;
+       }
+
+       retval = ext2fs_write_inode(fs, ino, &inode);
+       if (retval) {
+               com_err(__func__, retval,
+                       _("while writting inode %u"), ino);
+               goto end;
+       }
+
+end:
+       free(src_filename);
+       return retval;
+}
+
+static int is_dir(ext2_filsys fs, ext2_ino_t ino)
+{
+       struct ext2_inode inode;
+
+       if (ext2fs_read_inode(fs, ino, &inode))
+               return 0;
+       return S_ISDIR(inode.i_mode);
+}
+
+static errcode_t androidify_inode(ext2_filsys fs, ext2_ino_t ino,
+                                 struct inode_params *params)
+{
+       errcode_t retval;
+
+       retval = set_timestamp(fs, ino, params);
+       if (retval)
+               return retval;
+
+       retval = set_selinux_xattr(fs, ino, params);
+       if (retval)
+               return retval;
+
+       return set_perms_and_caps(fs, ino, params);
+}
+
+static int walk_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
+                   int flags EXT2FS_ATTR((unused)),
+                   struct ext2_dir_entry *de,
+                   int offset EXT2FS_ATTR((unused)),
+                   int blocksize EXT2FS_ATTR((unused)),
+                   char *buf EXT2FS_ATTR((unused)), void *priv_data)
+{
+       __u16 name_len;
+       errcode_t retval;
+       struct inode_params *params = (struct inode_params *)priv_data;
+
+       name_len = de->name_len & 0xff;
+       if (!strncmp(de->name, ".", name_len)
+           || (!strncmp(de->name, "..", name_len)))
+               return 0;
+
+       if (asprintf(&params->filename, "%s/%.*s", params->path, name_len,
+                    de->name) < 0)
+               return -ENOMEM;
+
+       if (!strncmp(de->name, "lost+found", 10)) {
+               retval = set_selinux_xattr(params->fs, de->inode, params);
+               if (retval)
+                       goto end;
+       } else {
+               retval = androidify_inode(params->fs, de->inode, params);
+               if (retval)
+                       goto end;
+               if (is_dir(params->fs, de->inode)) {
+                       char *cur_path = params->path;
+                       char *cur_filename = params->filename;
+                       params->path = params->filename;
+                       ext2fs_dir_iterate2(params->fs, de->inode, 0, NULL,
+                                           walk_dir, params);
+                       params->path = cur_path;
+                       params->filename = cur_filename;
+               }
+       }
+
+end:
+       free(params->filename);
+       return retval;
+}
+
+errcode_t __android_configure_fs(ext2_filsys fs, char *src_dir,
+                                char *target_out,
+                                char *mountpoint,
+                                fs_config_f fs_config_func,
+                                struct selabel_handle *sehnd,
+                                time_t fixed_time)
+{
+       errcode_t retval;
+       struct inode_params params = {
+               .fs = fs,
+               .src_dir = src_dir,
+               .target_out = target_out,
+               .fs_config_func = fs_config_func,
+               .sehnd = sehnd,
+               .fixed_time = fixed_time,
+               .path = mountpoint,
+               .filename = mountpoint,
+               .mountpoint = mountpoint,
+       };
+
+       /* walk_dir will add the "/". Don't add it twice. */
+       if (strlen(mountpoint) == 1 && mountpoint[0] == '/')
+               params.path = "";
+
+       retval = set_selinux_xattr(fs, EXT2_ROOT_INO, &params);
+       if (retval)
+               return retval;
+       retval = set_timestamp(fs, EXT2_ROOT_INO, &params);
+       if (retval)
+               return retval;
+
+       return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir,
+                                  &params);
+}
+
+errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out,
+                              char *mountpoint,
+                              struct selinux_opt *seopts,
+                              unsigned int nopt,
+                              char *fs_config_file, time_t fixed_time)
+{
+       errcode_t retval;
+       fs_config_f fs_config_func = NULL;
+       struct selabel_handle *sehnd = NULL;
+
+       /* Retrieve file contexts */
+       if (nopt > 0) {
+               sehnd = selabel_open(SELABEL_CTX_FILE, seopts, nopt);
+               if (!sehnd) {
+                       com_err(__func__, -EINVAL,
+                               _("while opening file contexts \"%s\""),
+                               seopts[0].value);
+                       return -EINVAL;
+               }
+       }
+
+       /* Load the FS config */
+       if (fs_config_file) {
+               retval = load_canned_fs_config(fs_config_file);
+               if (retval < 0) {
+                       com_err(__func__, retval,
+                               _("while loading fs_config \"%s\""),
+                               fs_config_file);
+                       return retval;
+               }
+               fs_config_func = canned_fs_config;
+       } else if (mountpoint)
+               fs_config_func = fs_config;
+
+       return __android_configure_fs(fs, src_dir, target_out, mountpoint,
+                                     fs_config_func, sehnd, fixed_time);
+}
diff --git a/contrib/android/perms.h b/contrib/android/perms.h
new file mode 100644 (file)
index 0000000..9955bb5
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef ANDROID_PERMS_H
+# define ANDROID_PERMS_H
+
+# include "config.h"
+# include <ext2fs/ext2fs.h>
+
+typedef void (*fs_config_f)(const char *path, int dir,
+                           const char *target_out_path,
+                           unsigned *uid, unsigned *gid,
+                           unsigned *mode, uint64_t *capabilities);
+
+# ifdef _WIN32
+struct selabel_handle;
+static inline errcode_t android_configure_fs(ext2_filsys fs,
+                                            char *src_dir,
+                                            char *target_out,
+                                            char *mountpoint,
+                                            void *seopts,
+                                            unsigned int nopt,
+                                            char *fs_config_file,
+                                            time_t fixed_time)
+{
+       return 0;
+}
+# else
+#  include <selinux/selinux.h>
+#  include <selinux/label.h>
+#  if !defined(HOST)
+#   include <selinux/android.h>
+#  endif
+#  include <private/android_filesystem_config.h>
+#  include <private/canned_fs_config.h>
+
+errcode_t android_configure_fs(ext2_filsys fs, char *src_dir,
+                              char *target_out,
+                              char *mountpoint,
+                              struct selinux_opt *seopts,
+                              unsigned int nopt,
+                              char *fs_config_file, time_t fixed_time);
+
+# endif
+#endif /* !ANDROID_PERMS_H */
diff --git a/debugfs/Android.bp b/debugfs/Android.bp
new file mode 100644 (file)
index 0000000..7dfc7d3
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2017 The Android Open Source Project
+
+//########################
+// Build the debugfs binary
+
+cc_defaults {
+    name: "debugfs-defaults",
+    srcs: [
+        "debug_cmds.c",
+        "debugfs.c",
+        "util.c",
+        "ncheck.c",
+        "icheck.c",
+        "ls.c",
+        "lsdel.c",
+        "dump.c",
+        "set_fields.c",
+        "logdump.c",
+        "htree.c",
+        "unused.c",
+        "e2freefrag.c",
+        "filefrag.c",
+        "extent_cmds.c",
+        "extent_inode.c",
+        "zap.c",
+        "quota.c",
+        "xattrs.c",
+        "journal.c",
+        "revoke.c",
+        "recovery.c",
+        "do_journal.c",
+    ],
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-macro-redefined",
+        "-fno-strict-aliasing",
+        "-DDEBUGFS",
+    ],
+    include_dirs: [
+        "external/e2fsprogs/misc",
+        "external/e2fsprogs/e2fsck"
+    ],
+}
+
+debugfs_libs = [
+    "libext2_misc",
+    "libext2fs",
+    "libext2_blkid",
+    "libext2_uuid",
+    "libext2_ss",
+    "libext2_quota",
+    "libext2_com_err",
+    "libext2_e2p",
+]
+
+cc_binary {
+    name: "debugfs",
+    host_supported: true,
+    defaults: ["debugfs-defaults"],
+
+    shared_libs: debugfs_libs,
+    system_shared_libs: ["libc"],
+}
+
+cc_binary {
+    name: "debugfs_static",
+    static_executable: true,
+    defaults: ["debugfs-defaults"],
+
+    static_libs: debugfs_libs + ["libc"],
+}
diff --git a/debugfs/Android.mk b/debugfs/Android.mk
deleted file mode 100644 (file)
index 91dc8c3..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-#########################
-# Build the debugfs binary
-
-debugfs_src_files :=  \
-       debug_cmds.c \
-       debugfs.c \
-       util.c \
-       ncheck.c\
-       icheck.c \
-       ls.c \
-       lsdel.c \
-       dump.c \
-       set_fields.c \
-       logdump.c \
-       htree.c \
-       unused.c \
-       e2freefrag.c \
-       filefrag.c \
-       extent_cmds.c \
-       extent_inode.c \
-       zap.c \
-       create_inode.c \
-       quota.c \
-       xattrs.c \
-       journal.c \
-       revoke.c \
-       recovery.c \
-       do_journal.c
-
-debugfs_shared_libraries := \
-       libext2fs \
-       libext2_blkid \
-       libext2_uuid \
-       libext2_ss \
-       libext2_quota \
-       libext2_com_err \
-       libext2_e2p
-
-debugfs_system_shared_libraries := libc
-
-debugfs_static_libraries := \
-       libext2fs \
-       libext2_blkid \
-       libext2_uuid_static \
-       libext2_ss \
-       libext2_quota \
-       libext2_com_err \
-       libext2_e2p
-
-debugfs_system_static_libraries := libc
-
-debugfs_c_includes := \
-       external/e2fsprogs/e2fsck \
-       external/e2fsprogs/misc \
-       external/e2fsprogs/lib
-
-debugfs_cflags := -O2 -g -W -Wall -fno-strict-aliasing -DDEBUGFS
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(debugfs_src_files)
-LOCAL_C_INCLUDES := $(debugfs_c_includes)
-LOCAL_CFLAGS := $(debugfs_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(debugfs_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(debugfs_shared_libraries)
-LOCAL_MODULE := debugfs
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(debugfs_src_files)
-LOCAL_C_INCLUDES := $(debugfs_c_includes)
-LOCAL_CFLAGS := $(debugfs_cflags)
-LOCAL_STATIC_LIBRARIES := $(debugfs_static_libraries) $(debugfs_system_static_libraries)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE := debugfs_static
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(debugfs_src_files)
-LOCAL_C_INCLUDES := $(debugfs_c_includes)
-LOCAL_CFLAGS := $(debugfs_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(debugfs_shared_libraries))
-LOCAL_MODULE := debugfs_host
-LOCAL_MODULE_STEM := debugfs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
index 3ac80d9b9b018db7f83abd1e2c4c85d1ac082dc7..408a3236694d18201e56492cb4eb0d8b35a5538a 100644 (file)
@@ -164,7 +164,7 @@ tst_set_fields: set_fields.c util.c
        $(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(SYSLIBS) -DUNITTEST \
                -o tst_set_fields $(srcdir)/set_fields.c $(srcdir)/util.c $(LIBS)
 
-check:: tst_set_fields
+fullcheck check:: tst_set_fields
        $(TESTENV) ./tst_set_fields
 
 # +++ Dependency line eater +++
index 453f5b52281543d135c56d61417767c0c6ac927c..0a4b536bc25afa06f23098f8ba81428614097a18 100644 (file)
@@ -778,41 +778,31 @@ static void dump_inline_data(FILE *out, const char *prefix, ext2_ino_t inode_num
                fprintf(out, "%sSize of inline data: %zu\n", prefix, size);
 }
 
-static void dump_fast_link(FILE *out, ext2_ino_t inode_num,
-                          struct ext2_inode *inode, const char *prefix)
+static void dump_inline_symlink(FILE *out, ext2_ino_t inode_num,
+                               struct ext2_inode *inode, const char *prefix)
 {
-       errcode_t retval = 0;
-       char *buf;
+       errcode_t retval;
+       char *buf = NULL;
        size_t size;
 
-       if (inode->i_flags & EXT4_INLINE_DATA_FL) {
-               retval = ext2fs_inline_data_size(current_fs, inode_num, &size);
-               if (retval)
-                       goto out;
-
-               retval = ext2fs_get_memzero(size + 1, &buf);
-               if (retval)
-                       goto out;
+       retval = ext2fs_inline_data_size(current_fs, inode_num, &size);
+       if (retval)
+               goto out;
 
-               retval = ext2fs_inline_data_get(current_fs, inode_num,
-                                               inode, buf, &size);
-               if (retval)
-                       goto out;
-               fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix,
-                       (int)size, buf);
+       retval = ext2fs_get_memzero(size + 1, &buf);
+       if (retval)
+               goto out;
 
-               retval = ext2fs_free_mem(&buf);
-               if (retval)
-                       goto out;
-       } else {
-               size_t sz = EXT2_I_SIZE(inode);
+       retval = ext2fs_inline_data_get(current_fs, inode_num,
+                                       inode, buf, &size);
+       if (retval)
+               goto out;
 
-               if (sz > sizeof(inode->i_block))
-                       sz = sizeof(inode->i_block);
-               fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix, (int) sz,
-                       (char *)inode->i_block);
-       }
+       fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix,
+               (int)size, buf);
 out:
+       if (buf)
+               ext2fs_free_mem(&buf);
        if (retval)
                com_err(__func__, retval, "while dumping link destination");
 }
@@ -861,16 +851,15 @@ void internal_dump_inode(FILE *out, const char *prefix,
                fprintf(out, "%d\n", inode->i_size);
        if (os == EXT2_OS_HURD)
                fprintf(out,
-                       "%sFile ACL: %d    Directory ACL: %d Translator: %d\n",
+                       "%sFile ACL: %d Translator: %d\n",
                        prefix,
-                       inode->i_file_acl, LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0,
+                       inode->i_file_acl,
                        inode->osd1.hurd1.h_i_translator);
        else
-               fprintf(out, "%sFile ACL: %llu    Directory ACL: %d\n",
+               fprintf(out, "%sFile ACL: %llu\n",
                        prefix,
                        inode->i_file_acl | ((long long)
-                               (inode->osd2.linux2.l_i_file_acl_high) << 32),
-                       LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0);
+                               (inode->osd2.linux2.l_i_file_acl_high) << 32));
        if (os != EXT2_OS_HURD)
                fprintf(out, "%sLinks: %d   Blockcount: %llu\n",
                        prefix, inode->i_links_count,
@@ -939,9 +928,12 @@ void internal_dump_inode(FILE *out, const char *prefix,
                fprintf(out, "Inode checksum: 0x%08x\n", crc);
        }
 
-       if (LINUX_S_ISLNK(inode->i_mode) &&
-           ext2fs_inode_data_blocks(current_fs, inode) == 0)
-               dump_fast_link(out, inode_num, inode, prefix);
+       if (LINUX_S_ISLNK(inode->i_mode) && ext2fs_is_fast_symlink(inode))
+               fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix,
+                       (int)EXT2_I_SIZE(inode), (char *)inode->i_block);
+       else if (LINUX_S_ISLNK(inode->i_mode) &&
+                  (inode->i_flags & EXT4_INLINE_DATA_FL))
+               dump_inline_symlink(out, inode_num, inode, prefix);
        else if (LINUX_S_ISBLK(inode->i_mode) || LINUX_S_ISCHR(inode->i_mode)) {
                int major, minor;
                const char *devnote;
@@ -1367,10 +1359,9 @@ void do_modify_inode(int argc, char *argv[])
        modify_u32(argv[0], "Reserved1", decimal_format, &inode.i_reserved1);
 #endif
        modify_u32(argv[0], "File acl", decimal_format, &inode.i_file_acl);
-       if (LINUX_S_ISDIR(inode.i_mode))
-               modify_u32(argv[0], "Directory acl", decimal_format, &inode.i_dir_acl);
-       else
-               modify_u32(argv[0], "High 32bits of size", decimal_format, &inode.i_size_high);
+
+       modify_u32(argv[0], "High 32bits of size", decimal_format,
+                  &inode.i_size_high);
 
        if (os == EXT2_OS_HURD)
                modify_u32(argv[0], "Translator Block",
index 4d3865153ce0d87945bf5182cdd570363e56a518..4d5daf0ac5ebf9549f636e267744d0a77ebb5826 100644 (file)
@@ -208,9 +208,7 @@ static void rdump_symlink(ext2_ino_t ino, struct ext2_inode *inode,
                goto errout;
        }
 
-       /* Apparently, this is the right way to detect and handle fast
-        * symlinks; see do_stat() in debugfs.c. */
-       if (ext2fs_inode_data_blocks2(current_fs, inode) == 0)
+       if (ext2fs_is_fast_symlink(inode))
                strcpy(buf, (char *) inode->i_block);
        else {
                unsigned bytes = inode->i_size;
index 54e55e20a73a195acc1d0e5c5d6299113865a4a1..8c18666d626f4705fd1a1f0575c81fdefbf90437 100644 (file)
@@ -287,7 +287,8 @@ void do_htree_dump(int argc, char *argv[])
        fprintf(pager, "\t Indirect levels: %d\n", rootnode->indirect_levels);
        fprintf(pager, "\t Flags: %d\n", rootnode->unused_flags);
 
-       ent = (struct ext2_dx_entry *) (buf + 24 + rootnode->info_length);
+       ent = (struct ext2_dx_entry *)
+               ((char *)rootnode + rootnode->info_length);
 
        htree_dump_int_node(current_fs, ino, &inode, rootnode, ent,
                            buf + current_fs->blocksize,
index ff9b7b6946deb3f5da18f45fed25a91d06a3c465..ca688622b09eb169d00c4f6456637a2ce68a5f4a 100644 (file)
@@ -212,7 +212,6 @@ static struct field_set_info inode_fields[] = {
        /* Special case: i_file_acl_high is 2 bytes */
        { "file_acl", &set_inode.i_file_acl, 
                &set_inode.osd2.linux2.l_i_file_acl_high, 6, parse_uint },
-       { "dir_acl", &set_inode.i_dir_acl, NULL, 4, parse_uint, FLAG_ALIAS },
        { "faddr", &set_inode.i_faddr, NULL, 4, parse_uint },
        { "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint, FLAG_ALIAS },
        { "fsize", &set_inode.osd2.hurd2.h_i_fsize, NULL, 1, parse_uint },
index 9b87d14551dca89498c9415415692f8bdeae2757..fdb76e41a230c1236ec846c8dc4d086a5d15f1d6 100644 (file)
@@ -306,13 +306,6 @@ void do_set_xattr(int argc, char **argv)
        }
 
        err = ext2fs_xattr_set(h, argv[optind + 1], buf, buflen);
-       if (err)
-               goto out;
-
-       err = ext2fs_xattrs_write(h);
-       if (err)
-               goto out;
-
 out:
        ext2fs_xattrs_close(&h);
        if (err)
@@ -360,10 +353,6 @@ void do_rm_xattr(int argc, char **argv)
                if (err)
                        goto out;
        }
-
-       err = ext2fs_xattrs_write(h);
-       if (err)
-               goto out;
 out:
        ext2fs_xattrs_close(&h);
        if (err)
diff --git a/e2fsck/Android.bp b/e2fsck/Android.bp
new file mode 100644 (file)
index 0000000..1cabe86
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2017 The Android Open Source Project
+
+//########################
+// Build the e2fsck binary
+
+cc_defaults {
+    name: "e2fsck-defaults",
+    srcs: [
+        "e2fsck.c",
+        "super.c",
+        "pass1.c",
+        "pass1b.c",
+        "pass2.c",
+        "pass3.c",
+        "pass4.c",
+        "pass5.c",
+        "logfile.c",
+        "journal.c",
+        "recovery.c",
+        "revoke.c",
+        "badblocks.c",
+        "util.c",
+        "unix.c",
+        "dirinfo.c",
+        "dx_dirinfo.c",
+        "ehandler.c",
+        "problem.c",
+        "message.c",
+        "ea_refcount.c",
+        "quota.c",
+        "rehash.c",
+        "region.c",
+        "sigcatcher.c",
+        "readahead.c",
+        "extents.c",
+    ],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined", "-fno-strict-aliasing"],
+}
+
+e2fsck_libs = [
+    "libext2fs",
+    "libext2_blkid",
+    "libext2_uuid",
+    "libext2_quota",
+    "libext2_com_err",
+    "libext2_e2p",
+]
+
+cc_binary {
+    name: "e2fsck",
+    host_supported: true,
+    defaults: ["e2fsck-defaults"],
+
+    shared_libs: e2fsck_libs,
+    system_shared_libs: ["libc"],
+}
+
+cc_binary {
+    name: "e2fsck_static",
+    static_executable: true,
+    defaults: ["e2fsck-defaults"],
+
+    static_libs: e2fsck_libs + ["libc"],
+}
diff --git a/e2fsck/Android.mk b/e2fsck/Android.mk
deleted file mode 100644 (file)
index 604eaa1..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-#########################
-# Build the e2fsck binary
-
-e2fsck_src_files :=  \
-       e2fsck.c \
-       super.c \
-       pass1.c \
-       pass1b.c \
-       pass2.c \
-       pass3.c \
-       pass4.c \
-       pass5.c \
-       logfile.c \
-       journal.c \
-       recovery.c \
-       revoke.c \
-       badblocks.c \
-       util.c \
-       unix.c \
-       dirinfo.c \
-       dx_dirinfo.c \
-       ehandler.c \
-       problem.c \
-       message.c \
-       ea_refcount.c \
-       quota.c \
-       rehash.c \
-       region.c \
-       sigcatcher.c \
-       readahead.c \
-       extents.c
-
-e2fsck_shared_libraries := \
-       libext2fs \
-       libext2_blkid \
-       libext2_uuid \
-       libext2_quota \
-       libext2_com_err \
-       libext2_e2p
-
-e2fsck_system_shared_libraries := libc
-
-e2fsck_static_libraries := \
-       libext2fs \
-       libext2_blkid \
-       libext2_uuid_static \
-       libext2_quota \
-       libext2_com_err \
-       libext2_e2p
-
-e2fsck_system_static_libraries := libc
-
-e2fsck_c_includes :=
-
-e2fsck_cflags := -O2 -g -W -Wall -fno-strict-aliasing
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2fsck_src_files)
-LOCAL_C_INCLUDES := $(e2fsck_c_includes)
-LOCAL_CFLAGS := $(e2fsck_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(e2fsck_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(e2fsck_shared_libraries)
-LOCAL_MODULE := e2fsck
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2fsck_src_files)
-LOCAL_C_INCLUDES := $(e2fsck_c_includes)
-LOCAL_CFLAGS := $(e2fsck_cflags)
-LOCAL_STATIC_LIBRARIES := $(e2fsck_static_libraries) $(e2fsck_system_static_libraries)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE := e2fsck_static
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2fsck_src_files)
-LOCAL_C_INCLUDES := $(e2fsck_c_includes)
-LOCAL_CFLAGS := $(e2fsck_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(e2fsck_shared_libraries))
-LOCAL_MODULE := e2fsck_host
-LOCAL_MODULE_STEM := e2fsck
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
index cee6a42b5360f2a151de8a488b39c48b2447fa64..e43d34049147633e9d87c33da019f88d979dfb1a 100644 (file)
@@ -150,7 +150,7 @@ tst_region: region.c $(DEPLIBCOM_ERR)
                $(ALL_CFLAGS) $(ALL_LDFLAGS) -DTEST_PROGRAM \
                $(LIBCOM_ERR) $(SYSLIBS)
 
-check:: tst_refcount tst_region tst_problem
+fullcheck check:: tst_refcount tst_region tst_problem
        $(TESTENV) ./tst_refcount
        $(TESTENV) ./tst_region
        $(TESTENV) ./tst_problem
index 0f9da46a5a12b6cebfde125b1409962fbcd31558..88088a2578bb6542209dd56999dfe565c6143105 100644 (file)
@@ -98,6 +98,18 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)
                ea_refcount_free(ctx->refcount_extra);
                ctx->refcount_extra = 0;
        }
+       if (ctx->ea_block_quota_blocks) {
+               ea_refcount_free(ctx->ea_block_quota_blocks);
+               ctx->ea_block_quota_blocks = 0;
+       }
+       if (ctx->ea_block_quota_inodes) {
+               ea_refcount_free(ctx->ea_block_quota_inodes);
+               ctx->ea_block_quota_inodes = 0;
+       }
+       if (ctx->ea_inode_refs) {
+               ea_refcount_free(ctx->ea_inode_refs);
+               ctx->ea_inode_refs = 0;
+       }
        if (ctx->block_dup_map) {
                ext2fs_free_block_bitmap(ctx->block_dup_map);
                ctx->block_dup_map = 0;
index 81c09d7eb086c25bc6d4a877d930720a288b9a44..222f47c69cd7d234dfd5c35af849b83b16e189ec 100644 (file)
@@ -122,6 +122,7 @@ struct dx_dirblock_info {
        blk64_t         phys;
        int             flags;
        blk64_t         parent;
+       blk64_t         previous;
        ext2_dirhash_t  min_hash;
        ext2_dirhash_t  max_hash;
        ext2_dirhash_t  node_min_hash;
@@ -267,6 +268,17 @@ struct e2fsck_struct {
        ext2_refcount_t refcount;
        ext2_refcount_t refcount_extra;
 
+       /*
+        * Quota blocks and inodes to be charged for each ea block.
+        */
+       ext2_refcount_t ea_block_quota_blocks;
+       ext2_refcount_t ea_block_quota_inodes;
+
+       /*
+        * ea_inode references from attr entries.
+        */
+       ext2_refcount_t ea_inode_refs;
+
        /*
         * Array of flags indicating whether an inode bitmap, block
         * bitmap, or inode table is invalid
@@ -464,18 +476,23 @@ extern int e2fsck_get_num_dx_dirinfo(e2fsck_t ctx);
 extern struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control);
 
 /* ea_refcount.c */
-extern errcode_t ea_refcount_create(int size, ext2_refcount_t *ret);
+typedef __u64 ea_key_t;
+typedef __u64 ea_value_t;
+
+extern errcode_t ea_refcount_create(size_t size, ext2_refcount_t *ret);
 extern void ea_refcount_free(ext2_refcount_t refcount);
-extern errcode_t ea_refcount_fetch(ext2_refcount_t refcount, blk64_t blk, int *ret);
+extern errcode_t ea_refcount_fetch(ext2_refcount_t refcount, ea_key_t ea_key,
+                                  ea_value_t *ret);
 extern errcode_t ea_refcount_increment(ext2_refcount_t refcount,
-                                      blk64_t blk, int *ret);
+                                      ea_key_t ea_key, ea_value_t *ret);
 extern errcode_t ea_refcount_decrement(ext2_refcount_t refcount,
-                                      blk64_t blk, int *ret);
-extern errcode_t ea_refcount_store(ext2_refcount_t refcount,
-                                  blk64_t blk, int count);
-extern blk_t ext2fs_get_refcount_size(ext2_refcount_t refcount);
+                                      ea_key_t ea_key, ea_value_t *ret);
+extern errcode_t ea_refcount_store(ext2_refcount_t refcount, ea_key_t ea_key,
+                                  ea_value_t count);
+extern size_t ext2fs_get_refcount_size(ext2_refcount_t refcount);
 extern void ea_refcount_intr_begin(ext2_refcount_t refcount);
-extern blk64_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret);
+extern ea_key_t ea_refcount_intr_next(ext2_refcount_t refcount,
+                                     ea_value_t *ret);
 
 /* ehandler.c */
 extern const char *ehandler_operation(const char *op);
@@ -648,4 +665,7 @@ unsigned long long get_memory_size(void);
 extern void e2fsck_clear_progbar(e2fsck_t ctx);
 extern int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
                                  float percent, unsigned int dpynum);
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
 #endif /* _E2FSCK_H */
index fcfaf4970ece2d34ccd941648a71e9b235071251..ecb198640c6905f52077f03c71bf69bc92c6b573 100644 (file)
  * checked, its bit is set in the block_ea_map bitmap.
  */
 struct ea_refcount_el {
-       blk64_t ea_blk;
-       int     ea_count;
+       /* ea_key could either be an inode number or block number. */
+       ea_key_t        ea_key;
+       ea_value_t      ea_value;
 };
 
 struct ea_refcount {
-       blk_t           count;
-       blk_t           size;
-       blk_t           cursor;
+       size_t          count;
+       size_t          size;
+       size_t          cursor;
        struct ea_refcount_el   *list;
 };
 
@@ -46,7 +47,7 @@ void ea_refcount_free(ext2_refcount_t refcount)
        ext2fs_free_mem(&refcount);
 }
 
-errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
+errcode_t ea_refcount_create(size_t size, ext2_refcount_t *ret)
 {
        ext2_refcount_t refcount;
        errcode_t       retval;
@@ -60,9 +61,9 @@ errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
        if (!size)
                size = 500;
        refcount->size = size;
-       bytes = (size_t) (size * sizeof(struct ea_refcount_el));
+       bytes = size * sizeof(struct ea_refcount_el);
 #ifdef DEBUG
-       printf("Refcount allocated %d entries, %d bytes.\n",
+       printf("Refcount allocated %zu entries, %zu bytes.\n",
               refcount->size, bytes);
 #endif
        retval = ext2fs_get_mem(bytes, &refcount->list);
@@ -92,14 +93,14 @@ static void refcount_collapse(ext2_refcount_t refcount)
 
        list = refcount->list;
        for (i = 0, j = 0; i < refcount->count; i++) {
-               if (list[i].ea_count) {
+               if (list[i].ea_value) {
                        if (i != j)
                                list[j] = list[i];
                        j++;
                }
        }
 #if defined(DEBUG) || defined(TEST_PROGRAM)
-       printf("Refcount_collapse: size was %d, now %d\n",
+       printf("Refcount_collapse: size was %zu, now %d\n",
               refcount->count, j);
 #endif
        refcount->count = j;
@@ -111,11 +112,11 @@ static void refcount_collapse(ext2_refcount_t refcount)
  *     specified position.
  */
 static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
-                                                blk64_t blk, int pos)
+                                                ea_key_t ea_key, int pos)
 {
        struct ea_refcount_el   *el;
        errcode_t               retval;
-       blk_t                   new_size = 0;
+       size_t                  new_size = 0;
        int                     num;
 
        if (refcount->count >= refcount->size) {
@@ -141,8 +142,8 @@ static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
        }
        refcount->count++;
        el = &refcount->list[pos];
-       el->ea_count = 0;
-       el->ea_blk = blk;
+       el->ea_key = ea_key;
+       el->ea_value = 0;
        return el;
 }
 
@@ -153,7 +154,7 @@ static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
  *     and we can't find an entry, create one in the sorted list.
  */
 static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
-                                             blk64_t blk, int create)
+                                             ea_key_t ea_key, int create)
 {
        int     low, high, mid;
 
@@ -163,11 +164,11 @@ retry:
        low = 0;
        high = (int) refcount->count-1;
        if (create && ((refcount->count == 0) ||
-                      (blk > refcount->list[high].ea_blk))) {
+                      (ea_key > refcount->list[high].ea_key))) {
                if (refcount->count >= refcount->size)
                        refcount_collapse(refcount);
 
-               return insert_refcount_el(refcount, blk,
+               return insert_refcount_el(refcount, ea_key,
                                          (unsigned) refcount->count);
        }
        if (refcount->count == 0)
@@ -175,18 +176,18 @@ retry:
 
        if (refcount->cursor >= refcount->count)
                refcount->cursor = 0;
-       if (blk == refcount->list[refcount->cursor].ea_blk)
+       if (ea_key == refcount->list[refcount->cursor].ea_key)
                return &refcount->list[refcount->cursor++];
 #ifdef DEBUG
-       printf("Non-cursor get_refcount_el: %u\n", blk);
+       printf("Non-cursor get_refcount_el: %u\n", ea_key);
 #endif
        while (low <= high) {
                mid = (low+high)/2;
-               if (blk == refcount->list[mid].ea_blk) {
+               if (ea_key == refcount->list[mid].ea_key) {
                        refcount->cursor = mid+1;
                        return &refcount->list[mid];
                }
-               if (blk < refcount->list[mid].ea_blk)
+               if (ea_key < refcount->list[mid].ea_key)
                        high = mid-1;
                else
                        low = mid+1;
@@ -201,69 +202,72 @@ retry:
                        if (refcount->count < refcount->size)
                                goto retry;
                }
-               return insert_refcount_el(refcount, blk, low);
+               return insert_refcount_el(refcount, ea_key, low);
        }
        return 0;
 }
 
-errcode_t ea_refcount_fetch(ext2_refcount_t refcount, blk64_t blk,
-                               int *ret)
+errcode_t ea_refcount_fetch(ext2_refcount_t refcount, ea_key_t ea_key,
+                           ea_value_t *ret)
 {
        struct ea_refcount_el   *el;
 
-       el = get_refcount_el(refcount, blk, 0);
+       el = get_refcount_el(refcount, ea_key, 0);
        if (!el) {
                *ret = 0;
                return 0;
        }
-       *ret = el->ea_count;
+       *ret = el->ea_value;
        return 0;
 }
 
-errcode_t ea_refcount_increment(ext2_refcount_t refcount, blk64_t blk, int *ret)
+errcode_t ea_refcount_increment(ext2_refcount_t refcount, ea_key_t ea_key,
+                               ea_value_t *ret)
 {
        struct ea_refcount_el   *el;
 
-       el = get_refcount_el(refcount, blk, 1);
+       el = get_refcount_el(refcount, ea_key, 1);
        if (!el)
                return EXT2_ET_NO_MEMORY;
-       el->ea_count++;
+       el->ea_value++;
 
        if (ret)
-               *ret = el->ea_count;
+               *ret = el->ea_value;
        return 0;
 }
 
-errcode_t ea_refcount_decrement(ext2_refcount_t refcount, blk64_t blk, int *ret)
+errcode_t ea_refcount_decrement(ext2_refcount_t refcount, ea_key_t ea_key,
+                               ea_value_t *ret)
 {
        struct ea_refcount_el   *el;
 
-       el = get_refcount_el(refcount, blk, 0);
-       if (!el || el->ea_count == 0)
+       el = get_refcount_el(refcount, ea_key, 0);
+       if (!el || el->ea_value == 0)
                return EXT2_ET_INVALID_ARGUMENT;
 
-       el->ea_count--;
+       el->ea_value--;
 
        if (ret)
-               *ret = el->ea_count;
+               *ret = el->ea_value;
        return 0;
 }
 
-errcode_t ea_refcount_store(ext2_refcount_t refcount, blk64_t blk, int count)
+errcode_t ea_refcount_store(ext2_refcount_t refcount, ea_key_t ea_key,
+                           ea_value_t ea_value)
 {
        struct ea_refcount_el   *el;
 
        /*
         * Get the refcount element
         */
-       el = get_refcount_el(refcount, blk, count ? 1 : 0);
+       el = get_refcount_el(refcount, ea_key, ea_value ? 1 : 0);
        if (!el)
-               return count ? EXT2_ET_NO_MEMORY : 0;
-       el->ea_count = count;
+               return ea_value ? EXT2_ET_NO_MEMORY : 0;
+       el->ea_value = ea_value;
        return 0;
 }
 
-blk_t ext2fs_get_refcount_size(ext2_refcount_t refcount)
+size_t ext2fs_get_refcount_size(ext2_refcount_t refcount)
 {
        if (!refcount)
                return 0;
@@ -276,9 +280,8 @@ void ea_refcount_intr_begin(ext2_refcount_t refcount)
        refcount->cursor = 0;
 }
 
-
-blk64_t ea_refcount_intr_next(ext2_refcount_t refcount,
-                               int *ret)
+ea_key_t ea_refcount_intr_next(ext2_refcount_t refcount,
+                               ea_value_t *ret)
 {
        struct ea_refcount_el   *list;
 
@@ -286,10 +289,10 @@ blk64_t ea_refcount_intr_next(ext2_refcount_t refcount,
                if (refcount->cursor >= refcount->count)
                        return 0;
                list = refcount->list;
-               if (list[refcount->cursor].ea_count) {
+               if (list[refcount->cursor].ea_value) {
                        if (ret)
-                               *ret = list[refcount->cursor].ea_count;
-                       return list[refcount->cursor++].ea_blk;
+                               *ret = list[refcount->cursor].ea_value;
+                       return list[refcount->cursor++].ea_key;
                }
                refcount->cursor++;
        }
@@ -309,11 +312,11 @@ errcode_t ea_refcount_validate(ext2_refcount_t refcount, FILE *out)
                return EXT2_ET_INVALID_ARGUMENT;
        }
        for (i=1; i < refcount->count; i++) {
-               if (refcount->list[i-1].ea_blk >= refcount->list[i].ea_blk) {
+               if (refcount->list[i-1].ea_key >= refcount->list[i].ea_key) {
                        fprintf(out,
-                               "%s: list[%d].blk=%llu, list[%d].blk=%llu\n",
-                               bad, i-1, refcount->list[i-1].ea_blk,
-                               i, refcount->list[i].ea_blk);
+                               "%s: list[%d].ea_key=%llu, list[%d].ea_key=%llu\n",
+                               bad, i-1, refcount->list[i-1].ea_key, i,
+                               refcount->list[i].ea_key);
                        ret = EXT2_ET_INVALID_ARGUMENT;
                }
        }
@@ -370,8 +373,9 @@ int main(int argc, char **argv)
 {
        int     i = 0;
        ext2_refcount_t refcount;
-       int             size, arg;
-       blk64_t         blk;
+       size_t          size;
+       ea_key_t        ea_key;
+       ea_value_t      arg;
        errcode_t       retval;
 
        while (1) {
@@ -383,10 +387,10 @@ int main(int argc, char **argv)
                        retval = ea_refcount_create(size, &refcount);
                        if (retval) {
                                com_err("ea_refcount_create", retval,
-                                       "while creating size %d", size);
+                                       "while creating size %zu", size);
                                exit(1);
                        } else
-                               printf("Creating refcount with size %d\n",
+                               printf("Creating refcount with size %zu\n",
                                       size);
                        break;
                case BCODE_FREE:
@@ -395,43 +399,46 @@ int main(int argc, char **argv)
                        printf("Freeing refcount\n");
                        break;
                case BCODE_STORE:
-                       blk = (blk_t) bcode_program[i++];
+                       ea_key = (size_t) bcode_program[i++];
                        arg = bcode_program[i++];
-                       printf("Storing blk %llu with value %d\n", blk, arg);
-                       retval = ea_refcount_store(refcount, blk, arg);
+                       printf("Storing ea_key %llu with value %llu\n", ea_key,
+                              arg);
+                       retval = ea_refcount_store(refcount, ea_key, arg);
                        if (retval)
                                com_err("ea_refcount_store", retval,
-                                       "while storing blk %llu", blk);
+                                       "while storing ea_key %llu", ea_key);
                        break;
                case BCODE_FETCH:
-                       blk = (blk_t) bcode_program[i++];
-                       retval = ea_refcount_fetch(refcount, blk, &arg);
+                       ea_key = (size_t) bcode_program[i++];
+                       retval = ea_refcount_fetch(refcount, ea_key, &arg);
                        if (retval)
                                com_err("ea_refcount_fetch", retval,
-                                       "while fetching blk %llu", blk);
+                                       "while fetching ea_key %llu", ea_key);
                        else
-                               printf("bcode_fetch(%llu) returns %d\n",
-                                      blk, arg);
+                               printf("bcode_fetch(%llu) returns %llu\n",
+                                      ea_key, arg);
                        break;
                case BCODE_INCR:
-                       blk = (blk_t) bcode_program[i++];
-                       retval = ea_refcount_increment(refcount, blk, &arg);
+                       ea_key = (size_t) bcode_program[i++];
+                       retval = ea_refcount_increment(refcount, ea_key, &arg);
                        if (retval)
                                com_err("ea_refcount_increment", retval,
-                                       "while incrementing blk %llu", blk);
+                                       "while incrementing ea_key %llu",
+                                       ea_key);
                        else
-                               printf("bcode_increment(%llu) returns %d\n",
-                                      blk, arg);
+                               printf("bcode_increment(%llu) returns %llu\n",
+                                      ea_key, arg);
                        break;
                case BCODE_DECR:
-                       blk = (blk_t) bcode_program[i++];
-                       retval = ea_refcount_decrement(refcount, blk, &arg);
+                       ea_key = (size_t) bcode_program[i++];
+                       retval = ea_refcount_decrement(refcount, ea_key, &arg);
                        if (retval)
                                com_err("ea_refcount_decrement", retval,
-                                       "while decrementing blk %llu", blk);
+                                       "while decrementing ea_key %llu",
+                                       ea_key);
                        else
-                               printf("bcode_decrement(%llu) returns %d\n",
-                                      blk, arg);
+                               printf("bcode_decrement(%llu) returns %llu\n",
+                                      ea_key, arg);
                        break;
                case BCODE_VALIDATE:
                        retval = ea_refcount_validate(refcount, stderr);
@@ -444,10 +451,11 @@ int main(int argc, char **argv)
                case BCODE_LIST:
                        ea_refcount_intr_begin(refcount);
                        while (1) {
-                               blk = ea_refcount_intr_next(refcount, &arg);
-                               if (!blk)
+                               ea_key = ea_refcount_intr_next(refcount, &arg);
+                               if (!ea_key)
                                        break;
-                               printf("\tblk=%llu, count=%d\n", blk, arg);
+                               printf("\tea_key=%llu, count=%llu\n", ea_key,
+                                      arg);
                        }
                        break;
                case BCODE_COLLAPSE:
index a44205fc8476ff24eec905966c109205bee74bcc..7fc656925b5b0b4d0e555e1a00704f66f0e8a51f 100644 (file)
@@ -32,7 +32,7 @@
  *     %IM     <inode> -> i_mtime
  *     %IF     <inode> -> i_faddr
  *     %If     <inode> -> i_file_acl
- *     %Id     <inode> -> i_dir_acl
+ *     %Id     <inode> -> i_size_high
  *     %Iu     <inode> -> i_uid
  *     %Ig     <inode> -> i_gid
  *     %It     <inode type>
@@ -283,17 +283,8 @@ static _INLINE_ void expand_inode_expression(FILE *f, ext2_filsys fs, char ch,
        case 's':
                if (LINUX_S_ISDIR(inode->i_mode))
                        fprintf(f, "%u", inode->i_size);
-               else {
-#ifdef EXT2_NO_64_TYPE
-                       if (inode->i_size_high)
-                               fprintf(f, "0x%x%08x", inode->i_size_high,
-                                       inode->i_size);
-                       else
-                               fprintf(f, "%u", inode->i_size);
-#else
+               else
                        fprintf(f, "%llu", EXT2_I_SIZE(inode));
-#endif
-               }
                break;
        case 'S':
                fprintf(f, "%u", large_inode->i_extra_isize);
@@ -323,7 +314,7 @@ static _INLINE_ void expand_inode_expression(FILE *f, ext2_filsys fs, char ch,
                break;
        case 'd':
                fprintf(f, "%u", (LINUX_S_ISDIR(inode->i_mode) ?
-                                 inode->i_dir_acl : 0));
+                       inode->i_size_high : 0));
                break;
        case 'u':
                fprintf(f, "%d", inode_uid(*inode));
@@ -414,11 +405,7 @@ static _INLINE_ void expand_percent_expression(FILE *f, ext2_filsys fs,
                fputc('%', f);
                break;
        case 'b':
-#ifdef EXT2_NO_64_TYPE
-               fprintf(f, "%*u", width, (unsigned long) ctx->blk);
-#else
                fprintf(f, "%*llu", width, (unsigned long long) ctx->blk);
-#endif
                break;
        case 'B':
                if (ctx->blkcount == BLOCK_COUNT_IND)
@@ -434,20 +421,11 @@ static _INLINE_ void expand_percent_expression(FILE *f, ext2_filsys fs,
                if (*first && islower(m[0]))
                        fputc(toupper(*m++), f);
                fputs(m, f);
-               if (ctx->blkcount >= 0) {
-#ifdef EXT2_NO_64_TYPE
-                       fprintf(f, "%d", ctx->blkcount);
-#else
+               if (ctx->blkcount >= 0)
                        fprintf(f, "%lld", (long long) ctx->blkcount);
-#endif
-               }
                break;
        case 'c':
-#ifdef EXT2_NO_64_TYPE
-               fprintf(f, "%*u", width, (unsigned long) ctx->blk2);
-#else
                fprintf(f, "%*llu", width, (unsigned long long) ctx->blk2);
-#endif
                break;
        case 'd':
                fprintf(f, "%*u", width, ctx->dir);
@@ -465,11 +443,10 @@ static _INLINE_ void expand_percent_expression(FILE *f, ext2_filsys fs,
                fprintf(f, "%*s", width, error_message(ctx->errcode));
                break;
        case 'N':
-#ifdef EXT2_NO_64_TYPE
-               fprintf(f, "%*u", width, ctx->num);
-#else
                fprintf(f, "%*llu", width, (long long)ctx->num);
-#endif
+               break;
+       case 'n':
+               fprintf(f, "%*llu", width, (long long)ctx->num2);
                break;
        case 'p':
                print_pathname(f, fs, ctx->ino, 0);
@@ -485,11 +462,7 @@ static _INLINE_ void expand_percent_expression(FILE *f, ext2_filsys fs,
                print_pathname(f, fs, ctx->dir, ctx->ino);
                break;
        case 'r':
-#ifdef EXT2_NO_64_TYPE
-               fprintf(f, "%*d", width, ctx->blkcount);
-#else
                fprintf(f, "%*lld", width, (long long) ctx->blkcount);
-#endif
                break;
        case 'S':
                fprintf(f, "%llu", get_backup_sb(NULL, fs, NULL, NULL));
@@ -528,11 +501,7 @@ static _INLINE_ void expand_percent_expression(FILE *f, ext2_filsys fs,
                fprintf(f, "0x%0*x", width, ctx->csum1);
                break;
        case 'X':
-#ifdef EXT2_NO_64_TYPE
-               fprintf(f, "0x%0*x", width, ctx->num);
-#else
                fprintf(f, "0x%0*llx", width, (long long)ctx->num);
-#endif
                break;
        case 'y':
                fprintf(f, "0x%0*x", width, ctx->csum2);
index 8044beed6ce161fbedcce9d32ed37e291a201bcb..47a8b27c0d29f7dc008063e90cb9faa80af7eaca 100644 (file)
@@ -26,6 +26,7 @@
  *     - A bitmap of which blocks are in use.          (block_found_map)
  *     - A bitmap of which blocks are in use by two inodes     (block_dup_map)
  *     - The data blocks of the directory inodes.      (dir_map)
+ *     - Ref counts for ea_inodes.                     (ea_inode_refs)
  *
  * Pass 1 is designed to stash away enough information so that the
  * other passes should not need to read in the inode information
 
 #undef DEBUG
 
+struct ea_quota {
+       blk64_t blocks;
+       __u64 inodes;
+};
+
 static int process_block(ext2_filsys fs, blk64_t       *blocknr,
                         e2_blkcnt_t blockcnt, blk64_t ref_blk,
                         int ref_offset, void *priv_data);
@@ -65,7 +71,8 @@ static int process_bad_block(ext2_filsys fs, blk64_t *block_nr,
                             e2_blkcnt_t blockcnt, blk64_t ref_blk,
                             int ref_offset, void *priv_data);
 static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
-                        char *block_buf);
+                        char *block_buf,
+                        const struct ea_quota *ea_ibody_quota);
 static void mark_table_blocks(e2fsck_t ctx);
 static void alloc_bb_map(e2fsck_t ctx);
 static void alloc_imagic_map(e2fsck_t ctx);
@@ -102,6 +109,7 @@ struct process_block_struct {
 
 struct process_inode_block {
        ext2_ino_t ino;
+       struct ea_quota ea_ibody_quota;
        struct ext2_inode_large inode;
 };
 
@@ -177,7 +185,6 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
 {
        unsigned int len;
        int i;
-       blk64_t blocks;
        ext2_extent_handle_t    handle;
        struct ext2_extent_info info;
        struct ext2fs_extent    extent;
@@ -221,12 +228,15 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
                return 1;
        }
 
-       blocks = ext2fs_inode_data_blocks2(fs, inode);
-       if (blocks) {
-               if (inode->i_flags & EXT4_INLINE_DATA_FL)
+       if (ext2fs_is_fast_symlink(inode)) {
+               if (inode->i_size >= sizeof(inode->i_block))
+                       return 0;
+
+               len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
+               if (len == sizeof(inode->i_block))
                        return 0;
+       } else {
                if ((inode->i_size >= fs->blocksize) ||
-                   (blocks != fs->blocksize >> 9) ||
                    (inode->i_block[0] < fs->super->s_first_data_block) ||
                    (inode->i_block[0] >= ext2fs_blocks_count(fs->super)))
                        return 0;
@@ -245,34 +255,6 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
                }
                if (len == fs->blocksize)
                        return 0;
-       } else if (inode->i_flags & EXT4_INLINE_DATA_FL) {
-               char *inline_buf = NULL;
-               size_t inline_sz = 0;
-
-               if (ext2fs_inline_data_size(fs, ino, &inline_sz))
-                       return 0;
-               if (inode->i_size != inline_sz)
-                       return 0;
-               if (ext2fs_get_mem(inline_sz + 1, &inline_buf))
-                       return 0;
-               i = 0;
-               if (ext2fs_inline_data_get(fs, ino, inode, inline_buf, NULL))
-                       goto exit_inline;
-               inline_buf[inline_sz] = 0;
-               len = strnlen(inline_buf, inline_sz);
-               if (len != inline_sz)
-                       goto exit_inline;
-               i = 1;
-exit_inline:
-               ext2fs_free_mem(&inline_buf);
-               return i;
-       } else {
-               if (inode->i_size >= sizeof(inode->i_block))
-                       return 0;
-
-               len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
-               if (len == sizeof(inode->i_block))
-                       return 0;
        }
        if (len != inode->i_size)
                if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0)
@@ -333,21 +315,127 @@ static void check_size(e2fsck_t ctx, struct problem_context *pctx)
        e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
 }
 
-static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
+/*
+ * For a given size, calculate how many blocks would be charged towards quota.
+ */
+static blk64_t size_to_quota_blocks(ext2_filsys fs, size_t size)
+{
+       blk64_t clusters;
+
+       clusters = DIV_ROUND_UP(size, fs->blocksize << fs->cluster_ratio_bits);
+       return EXT2FS_C2B(fs, clusters);
+}
+
+/*
+ * Check validity of EA inode. Return 0 if EA inode is valid, otherwise return
+ * the problem code.
+ */
+static problem_t check_large_ea_inode(e2fsck_t ctx,
+                                     struct ext2_ext_attr_entry *entry,
+                                     struct problem_context *pctx,
+                                     blk64_t *quota_blocks)
+{
+       struct ext2_inode inode;
+       __u32 hash;
+       errcode_t retval;
+
+       /* Check if inode is within valid range */
+       if ((entry->e_value_inum < EXT2_FIRST_INODE(ctx->fs->super)) ||
+           (entry->e_value_inum > ctx->fs->super->s_inodes_count)) {
+               pctx->num = entry->e_value_inum;
+               return PR_1_ATTR_VALUE_EA_INODE;
+       }
+
+       e2fsck_read_inode(ctx, entry->e_value_inum, &inode, "pass1");
+
+       retval = ext2fs_ext_attr_hash_entry2(ctx->fs, entry, NULL, &hash);
+       if (retval) {
+               com_err("check_large_ea_inode", retval,
+                       _("while hashing entry with e_value_inum = %u"),
+                       entry->e_value_inum);
+               fatal_error(ctx, 0);
+       }
+
+       if (hash == entry->e_hash) {
+               *quota_blocks = size_to_quota_blocks(ctx->fs,
+                                                    entry->e_value_size);
+       } else {
+               /* This might be an old Lustre-style ea_inode reference. */
+               if (inode.i_mtime == pctx->ino &&
+                   inode.i_generation == pctx->inode->i_generation) {
+                       *quota_blocks = 0;
+               } else {
+                       /* If target inode is also missing EA_INODE flag,
+                        * this is likely to be a bad reference.
+                        */
+                       if (!(inode.i_flags & EXT4_EA_INODE_FL)) {
+                               pctx->num = entry->e_value_inum;
+                               return PR_1_ATTR_VALUE_EA_INODE;
+                       } else {
+                               pctx->num = entry->e_hash;
+                               return PR_1_ATTR_HASH;
+                       }
+               }
+       }
+
+       if (!(inode.i_flags & EXT4_EA_INODE_FL)) {
+               pctx->num = entry->e_value_inum;
+               if (fix_problem(ctx, PR_1_ATTR_SET_EA_INODE_FL, pctx)) {
+                       inode.i_flags |= EXT4_EA_INODE_FL;
+                       ext2fs_write_inode(ctx->fs, entry->e_value_inum,
+                                          &inode);
+               } else {
+                       return PR_1_ATTR_NO_EA_INODE_FL;
+               }
+       }
+       return 0;
+}
+
+static void inc_ea_inode_refs(e2fsck_t ctx, struct problem_context *pctx,
+                             struct ext2_ext_attr_entry *first, void *end)
+{
+       struct ext2_ext_attr_entry *entry;
+
+       for (entry = first;
+            (void *)entry < end && !EXT2_EXT_IS_LAST_ENTRY(entry);
+            entry = EXT2_EXT_ATTR_NEXT(entry)) {
+               if (!entry->e_value_inum)
+                       continue;
+               if (!ctx->ea_inode_refs) {
+                       pctx->errcode = ea_refcount_create(0,
+                                                          &ctx->ea_inode_refs);
+                       if (pctx->errcode) {
+                               pctx->num = 4;
+                               fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
+                               ctx->flags |= E2F_FLAG_ABORT;
+                               return;
+                       }
+               }
+               ea_refcount_increment(ctx->ea_inode_refs, entry->e_value_inum,
+                                     0);
+       }
+}
+
+static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx,
+                             struct ea_quota *ea_ibody_quota)
 {
        struct ext2_super_block *sb = ctx->fs->super;
        struct ext2_inode_large *inode;
        struct ext2_ext_attr_entry *entry;
-       char *start, *header;
+       char *start, *header, *end;
        unsigned int storage_size, remain;
        problem_t problem = 0;
        region_t region = 0;
 
+       ea_ibody_quota->blocks = 0;
+       ea_ibody_quota->inodes = 0;
+
        inode = (struct ext2_inode_large *) pctx->inode;
        storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
                inode->i_extra_isize;
        header = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
                 inode->i_extra_isize;
+       end = header + storage_size;
        start = header + sizeof(__u32);
        entry = (struct ext2_ext_attr_entry *) start;
 
@@ -391,38 +479,48 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
                /* attribute len eats this space */
                remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
 
-               /* check value size */
-               if (entry->e_value_size > remain) {
-                       pctx->num = entry->e_value_size;
-                       problem = PR_1_ATTR_VALUE_SIZE;
-                       goto fix;
-               }
+               if (entry->e_value_inum == 0) {
+                       /* check value size */
+                       if (entry->e_value_size > remain) {
+                               pctx->num = entry->e_value_size;
+                               problem = PR_1_ATTR_VALUE_SIZE;
+                               goto fix;
+                       }
 
-               /* e_value_block must be 0 in inode's ea */
-               if (entry->e_value_block != 0) {
-                       pctx->num = entry->e_value_block;
-                       problem = PR_1_ATTR_VALUE_BLOCK;
-                       goto fix;
-               }
+                       if (entry->e_value_size &&
+                           region_allocate(region,
+                                           sizeof(__u32) + entry->e_value_offs,
+                                           EXT2_EXT_ATTR_SIZE(
+                                               entry->e_value_size))) {
+                               problem = PR_1_INODE_EA_ALLOC_COLLISION;
+                               goto fix;
+                       }
 
-               if (entry->e_value_size &&
-                   region_allocate(region, sizeof(__u32) + entry->e_value_offs,
-                                   EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
-                       problem = PR_1_INODE_EA_ALLOC_COLLISION;
-                       goto fix;
-               }
+                       hash = ext2fs_ext_attr_hash_entry(entry,
+                                                         start + entry->e_value_offs);
+
+                       /* e_hash may be 0 in older inode's ea */
+                       if (entry->e_hash != 0 && entry->e_hash != hash) {
+                               pctx->num = entry->e_hash;
+                               problem = PR_1_ATTR_HASH;
+                               goto fix;
+                       }
+               } else {
+                       blk64_t quota_blocks;
 
-               hash = ext2fs_ext_attr_hash_entry(entry,
-                                                 start + entry->e_value_offs);
+                       problem = check_large_ea_inode(ctx, entry, pctx,
+                                                      &quota_blocks);
+                       if (problem != 0)
+                               goto fix;
 
-               /* e_hash may be 0 in older inode's ea */
-               if (entry->e_hash != 0 && entry->e_hash != hash) {
-                       pctx->num = entry->e_hash;
-                       problem = PR_1_ATTR_HASH;
-                       goto fix;
+                       ea_ibody_quota->blocks += quota_blocks;
+                       ea_ibody_quota->inodes++;
                }
 
-               remain -= entry->e_value_size;
+               /* If EA value is stored in external inode then it does not
+                * consume space here */
+               if (entry->e_value_inum == 0)
+                       remain -= entry->e_value_size;
 
                entry = EXT2_EXT_ATTR_NEXT(entry);
        }
@@ -439,13 +537,18 @@ fix:
         * it seems like a corruption. it's very unlikely we could repair
         * EA(s) in automatic fashion -bzzz
         */
-       if (problem == 0 || !fix_problem(ctx, problem, pctx))
+       if (problem == 0 || !fix_problem(ctx, problem, pctx)) {
+               inc_ea_inode_refs(ctx, pctx,
+                                 (struct ext2_ext_attr_entry *)start, end);
                return;
+       }
 
        /* simply remove all possible EA(s) */
        *((__u32 *)header) = 0UL;
        e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
                                EXT2_INODE_SIZE(sb), "pass1");
+       ea_ibody_quota->blocks = 0;
+       ea_ibody_quota->inodes = 0;
 }
 
 static int check_inode_extra_negative_epoch(__u32 xtime, __u32 extra) {
@@ -463,13 +566,17 @@ static int check_inode_extra_negative_epoch(__u32 xtime, __u32 extra) {
  */
 #define EXT4_EXTRA_NEGATIVE_DATE_CUTOFF 2 * (1LL << 32)
 
-static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
+static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx,
+                                   struct ea_quota *ea_ibody_quota)
 {
        struct ext2_super_block *sb = ctx->fs->super;
        struct ext2_inode_large *inode;
        __u32 *eamagic;
        int min, max;
 
+       ea_ibody_quota->blocks = 0;
+       ea_ibody_quota->inodes = 0;
+
        inode = (struct ext2_inode_large *) pctx->inode;
        if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
                /* this isn't large inode. so, nothing to check */
@@ -498,7 +605,6 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
                        inode->i_extra_isize = (inode->i_extra_isize + 3) & ~3;
                e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
                                        EXT2_INODE_SIZE(sb), "pass1");
-               return;
        }
 
        /* check if there is no place for an EA header */
@@ -509,7 +615,7 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
                        inode->i_extra_isize);
        if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
                /* it seems inode has an extended attribute(s) in body */
-               check_ea_in_inode(ctx, pctx);
+               check_ea_in_inode(ctx, pctx, ea_ibody_quota);
        }
 
        /*
@@ -1067,6 +1173,7 @@ void e2fsck_pass1(e2fsck_t ctx)
        int             failed_csum = 0;
        ext2_ino_t      ino_threshold = 0;
        dgrp_t          ra_group = 0;
+       struct ea_quota ea_ibody_quota;
 
        init_resource_track(&rtrack, ctx->fs->io);
        clear_problem_context(&pctx);
@@ -1612,7 +1719,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                                           "pass1");
                                        failed_csum = 0;
                                }
-                               check_blocks(ctx, &pctx, block_buf);
+                               check_blocks(ctx, &pctx, block_buf, NULL);
                                FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                                continue;
                        }
@@ -1639,7 +1746,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                                        "pass1");
                                        failed_csum = 0;
                                }
-                               check_blocks(ctx, &pctx, block_buf);
+                               check_blocks(ctx, &pctx, block_buf, NULL);
                                FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                                continue;
                        }
@@ -1677,7 +1784,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                        failed_csum = 0;
                                }
                        }
-                       check_blocks(ctx, &pctx, block_buf);
+                       check_blocks(ctx, &pctx, block_buf, NULL);
                        FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                        continue;
                }
@@ -1715,7 +1822,8 @@ void e2fsck_pass1(e2fsck_t ctx)
                }
 
                if (inode->i_faddr || frag || fsize ||
-                   (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
+                   (!ext2fs_has_feature_largedir(fs->super) &&
+                   (LINUX_S_ISDIR(inode->i_mode) && inode->i_size_high)))
                        mark_inode_bad(ctx, ino);
                if ((fs->super->s_creator_os != EXT2_OS_HURD) &&
                    !ext2fs_has_feature_64bit(fs->super) &&
@@ -1741,7 +1849,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                        }
                }
 
-               check_inode_extra_space(ctx, &pctx);
+               check_inode_extra_space(ctx, &pctx, &ea_ibody_quota);
                check_is_really_dir(ctx, &pctx, block_buf);
 
                /*
@@ -1786,9 +1894,10 @@ void e2fsck_pass1(e2fsck_t ctx)
                        if (inode->i_flags & EXT4_INLINE_DATA_FL) {
                                FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                                continue;
-                       } else if (ext2fs_inode_data_blocks(fs, inode) == 0) {
+                       } else if (ext2fs_is_fast_symlink(inode)) {
                                ctx->fs_fast_symlinks_count++;
-                               check_blocks(ctx, &pctx, block_buf);
+                               check_blocks(ctx, &pctx, block_buf,
+                                            &ea_ibody_quota);
                                FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                                continue;
                        }
@@ -1822,17 +1931,18 @@ void e2fsck_pass1(e2fsck_t ctx)
                     inode->i_block[EXT2_DIND_BLOCK] ||
                     inode->i_block[EXT2_TIND_BLOCK] ||
                     ext2fs_file_acl_block(fs, inode))) {
-                       struct ext2_inode_large *ip;
+                       struct process_inode_block *itp;
 
-                       inodes_to_process[process_inode_count].ino = ino;
-                       ip = &inodes_to_process[process_inode_count].inode;
+                       itp = &inodes_to_process[process_inode_count];
+                       itp->ino = ino;
+                       itp->ea_ibody_quota = ea_ibody_quota;
                        if (inode_size < sizeof(struct ext2_inode_large))
-                               memcpy(ip, inode, inode_size);
+                               memcpy(&itp->inode, inode, inode_size);
                        else
-                               memcpy(ip, inode, sizeof(*ip));
+                               memcpy(&itp->inode, inode, sizeof(itp->inode));
                        process_inode_count++;
                } else
-                       check_blocks(ctx, &pctx, block_buf);
+                       check_blocks(ctx, &pctx, block_buf, &ea_ibody_quota);
 
                FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
 
@@ -1870,6 +1980,16 @@ void e2fsck_pass1(e2fsck_t ctx)
                ctx->refcount_extra = 0;
        }
 
+       if (ctx->ea_block_quota_blocks) {
+               ea_refcount_free(ctx->ea_block_quota_blocks);
+               ctx->ea_block_quota_blocks = 0;
+       }
+
+       if (ctx->ea_block_quota_inodes) {
+               ea_refcount_free(ctx->ea_block_quota_inodes);
+               ctx->ea_block_quota_inodes = 0;
+       }
+
        if (ctx->invalid_bitmaps)
                handle_fs_bad_blocks(ctx);
 
@@ -2002,7 +2122,8 @@ static void process_inodes(e2fsck_t ctx, char *block_buf)
                sprintf(buf, _("reading indirect blocks of inode %u"),
                        pctx.ino);
                ehandler_operation(buf);
-               check_blocks(ctx, &pctx, block_buf);
+               check_blocks(ctx, &pctx, block_buf,
+                            &inodes_to_process[i].ea_ibody_quota);
                if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                        break;
        }
@@ -2154,14 +2275,20 @@ static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block)
        }
 }
 
+/*
+ * When cluster size is greater than one block, it is caller's responsibility
+ * to make sure block parameter starts at a cluster boundary.
+ */
 static _INLINE_ void mark_blocks_used(e2fsck_t ctx, blk64_t block,
                                      unsigned int num)
 {
        if (ext2fs_test_block_bitmap_range2(ctx->block_found_map, block, num))
                ext2fs_mark_block_bitmap_range2(ctx->block_found_map, block, num);
-       else
-               while (num--)
-                       mark_block_used(ctx, block++);
+       else {
+               int i;
+               for (i = 0; i < num; i += EXT2FS_CLUSTER_RATIO(ctx->fs))
+                       mark_block_used(ctx, block + i);
+       }
 }
 
 /*
@@ -2179,7 +2306,7 @@ static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
        ext2_filsys                     fs = ctx->fs;
        blk64_t                         blk;
        __u32                           should_be;
-       int                             count;
+       ea_value_t                      count;
 
        clear_problem_context(&pctx);
 
@@ -2196,7 +2323,7 @@ static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
                }
                header = (struct ext2_ext_attr_header *) block_buf;
                pctx.blkcount = header->h_refcount;
-               should_be = header->h_refcount + adjust_sign * count;
+               should_be = header->h_refcount + adjust_sign * (int)count;
                pctx.num = should_be;
                if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
                        header->h_refcount = should_be;
@@ -2216,7 +2343,7 @@ static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
  * Handle processing the extended attribute blocks
  */
 static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
-                          char *block_buf)
+                          char *block_buf, struct ea_quota *ea_block_quota)
 {
        ext2_filsys fs = ctx->fs;
        ext2_ino_t      ino = pctx->ino;
@@ -2224,11 +2351,15 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
        blk64_t         blk;
        char *          end;
        struct ext2_ext_attr_header *header;
-       struct ext2_ext_attr_entry *entry;
-       int             count;
+       struct ext2_ext_attr_entry *first, *entry;
+       blk64_t         quota_blocks = EXT2FS_C2B(fs, 1);
+       __u64           quota_inodes = 0;
        region_t        region = 0;
        int             failed_csum = 0;
 
+       ea_block_quota->blocks = 0;
+       ea_block_quota->inodes = 0;
+
        blk = ext2fs_file_acl_block(fs, inode);
        if (blk == 0)
                return 0;
@@ -2279,6 +2410,20 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
 
        /* Have we seen this EA block before? */
        if (ext2fs_fast_test_block_bitmap2(ctx->block_ea_map, blk)) {
+               ea_block_quota->blocks = EXT2FS_C2B(fs, 1);
+               ea_block_quota->inodes = 0;
+
+               if (ctx->ea_block_quota_blocks) {
+                       ea_refcount_fetch(ctx->ea_block_quota_blocks, blk,
+                                         &quota_blocks);
+                       if (quota_blocks)
+                               ea_block_quota->blocks = quota_blocks;
+               }
+
+               if (ctx->ea_block_quota_inodes)
+                       ea_refcount_fetch(ctx->ea_block_quota_inodes, blk,
+                                         &ea_block_quota->inodes);
+
                if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
                        return 1;
                /* Ooops, this EA was referenced more than it stated */
@@ -2342,8 +2487,9 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
                        goto clear_extattr;
        }
 
-       entry = (struct ext2_ext_attr_entry *)(header+1);
+       first = (struct ext2_ext_attr_entry *)(header+1);
        end = block_buf + fs->blocksize;
+       entry = first;
        while ((char *)entry < end && *(__u32 *)entry) {
                __u32 hash;
 
@@ -2361,30 +2507,41 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
                                goto clear_extattr;
                        break;
                }
-               if (entry->e_value_block != 0) {
-                       if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
-                               goto clear_extattr;
-               }
-               if (entry->e_value_offs + entry->e_value_size > fs->blocksize) {
-                       if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
-                               goto clear_extattr;
-                       break;
-               }
-               if (entry->e_value_size &&
-                   region_allocate(region, entry->e_value_offs,
-                                   EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
-                       if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
-                               goto clear_extattr;
-               }
+               if (entry->e_value_inum == 0) {
+                       if (entry->e_value_offs + entry->e_value_size >
+                           fs->blocksize) {
+                               if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
+                                       goto clear_extattr;
+                               break;
+                       }
+                       if (entry->e_value_size &&
+                           region_allocate(region, entry->e_value_offs,
+                                           EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
+                               if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION,
+                                               pctx))
+                                       goto clear_extattr;
+                       }
 
-               hash = ext2fs_ext_attr_hash_entry(entry, block_buf +
-                                                        entry->e_value_offs);
+                       hash = ext2fs_ext_attr_hash_entry(entry, block_buf +
+                                                         entry->e_value_offs);
+
+                       if (entry->e_hash != hash) {
+                               pctx->num = entry->e_hash;
+                               if (fix_problem(ctx, PR_1_ATTR_HASH, pctx))
+                                       goto clear_extattr;
+                               entry->e_hash = hash;
+                       }
+               } else {
+                       problem_t problem;
+                       blk64_t entry_quota_blocks;
 
-               if (entry->e_hash != hash) {
-                       pctx->num = entry->e_hash;
-                       if (fix_problem(ctx, PR_1_ATTR_HASH, pctx))
+                       problem = check_large_ea_inode(ctx, entry, pctx,
+                                                      &entry_quota_blocks);
+                       if (problem && fix_problem(ctx, problem, pctx))
                                goto clear_extattr;
-                       entry->e_hash = hash;
+
+                       quota_blocks += entry_quota_blocks;
+                       quota_inodes++;
                }
 
                entry = EXT2_EXT_ATTR_NEXT(entry);
@@ -2407,9 +2564,40 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
                        return 0;
        }
 
-       count = header->h_refcount - 1;
-       if (count)
-               ea_refcount_store(ctx->refcount, blk, count);
+       if (quota_blocks != EXT2FS_C2B(fs, 1)) {
+               if (!ctx->ea_block_quota_blocks) {
+                       pctx->errcode = ea_refcount_create(0,
+                                               &ctx->ea_block_quota_blocks);
+                       if (pctx->errcode) {
+                               pctx->num = 3;
+                               goto refcount_fail;
+                       }
+               }
+               ea_refcount_store(ctx->ea_block_quota_blocks, blk,
+                                 quota_blocks);
+       }
+
+       if (quota_inodes) {
+               if (!ctx->ea_block_quota_inodes) {
+                       pctx->errcode = ea_refcount_create(0,
+                                               &ctx->ea_block_quota_inodes);
+                       if (pctx->errcode) {
+                               pctx->num = 4;
+refcount_fail:
+                               fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
+                               ctx->flags |= E2F_FLAG_ABORT;
+                               return 0;
+                       }
+               }
+
+               ea_refcount_store(ctx->ea_block_quota_inodes, blk,
+                                 quota_inodes);
+       }
+       ea_block_quota->blocks = quota_blocks;
+       ea_block_quota->inodes = quota_inodes;
+
+       inc_ea_inode_refs(ctx, pctx, first, end);
+       ea_refcount_store(ctx->refcount, blk, header->h_refcount - 1);
        mark_block_used(ctx, blk);
        ext2fs_fast_mark_block_bitmap2(ctx->block_ea_map, blk);
        return 1;
@@ -2473,7 +2661,7 @@ static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
                return 1;
 
        pctx->num = root->indirect_levels;
-       if ((root->indirect_levels > 1) &&
+       if ((root->indirect_levels > ext2_dir_htree_level(fs)) &&
            fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
                return 1;
 
@@ -2561,8 +2749,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
 {
        struct ext2fs_extent    extent;
        blk64_t                 blk, last_lblk;
-       e2_blkcnt_t             blockcnt;
-       unsigned int            i;
+       unsigned int            i, n;
        int                     is_dir, is_leaf;
        problem_t               problem;
        struct ext2_extent_info info;
@@ -2829,50 +3016,29 @@ report_problem:
                        }
                }
 alloc_later:
-               while (is_dir && (++pb->last_db_block <
-                                 (e2_blkcnt_t) extent.e_lblk)) {
-                       pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist,
-                                                             pb->ino, 0,
-                                                             pb->last_db_block);
-                       if (pctx->errcode) {
-                               pctx->blk = 0;
-                               pctx->num = pb->last_db_block;
-                               goto failed_add_dir_block;
-                       }
-               }
-               if (!ctx->fs->cluster_ratio_bits) {
-                       mark_blocks_used(ctx, extent.e_pblk, extent.e_len);
-                       pb->num_blocks += extent.e_len;
-               }
-               for (blk = extent.e_pblk, blockcnt = extent.e_lblk, i = 0;
-                    i < extent.e_len;
-                    blk++, blockcnt++, i++) {
-                       if (ctx->fs->cluster_ratio_bits &&
-                           !(pb->previous_block &&
-                             (EXT2FS_B2C(ctx->fs, blk) ==
-                              EXT2FS_B2C(ctx->fs, pb->previous_block)) &&
-                             (blk & EXT2FS_CLUSTER_MASK(ctx->fs)) ==
-                             ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) {
-                               mark_block_used(ctx, blk);
-                               pb->num_blocks++;
-                       }
-                       if (has_unaligned_cluster_map(ctx, pb->previous_block,
-                                                     pb->last_block, blk,
-                                                     blockcnt)) {
-                               pctx->blk = blockcnt;
-                               pctx->blk2 = blk;
-                               fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
-                               mark_block_used(ctx, blk);
-                               mark_block_used(ctx, blk);
+               if (is_dir) {
+                       while (++pb->last_db_block <
+                              (e2_blkcnt_t) extent.e_lblk) {
+                               pctx->errcode = ext2fs_add_dir_block2(
+                                                       ctx->fs->dblist,
+                                                       pb->ino, 0,
+                                                       pb->last_db_block);
+                               if (pctx->errcode) {
+                                       pctx->blk = 0;
+                                       pctx->num = pb->last_db_block;
+                                       goto failed_add_dir_block;
+                               }
                        }
-                       pb->last_block = blockcnt;
-                       pb->previous_block = blk;
 
-                       if (is_dir) {
-                               pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pctx->ino, blk, blockcnt);
+                       for (i = 0; i < extent.e_len; i++) {
+                               pctx->errcode = ext2fs_add_dir_block2(
+                                                       ctx->fs->dblist,
+                                                       pctx->ino,
+                                                       extent.e_pblk + i,
+                                                       extent.e_lblk + i);
                                if (pctx->errcode) {
-                                       pctx->blk = blk;
-                                       pctx->num = blockcnt;
+                                       pctx->blk = extent.e_pblk + i;
+                                       pctx->num = extent.e_lblk + i;
                                failed_add_dir_block:
                                        fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
                                        /* Should never get here */
@@ -2880,9 +3046,46 @@ alloc_later:
                                        return;
                                }
                        }
+                       if (extent.e_len > 0)
+                               pb->last_db_block = extent.e_lblk + extent.e_len - 1;
+               }
+               if (has_unaligned_cluster_map(ctx, pb->previous_block,
+                                             pb->last_block,
+                                             extent.e_pblk,
+                                             extent.e_lblk)) {
+                       for (i = 0; i < extent.e_len; i++) {
+                               pctx->blk = extent.e_lblk + i;
+                               pctx->blk2 = extent.e_pblk + i;
+                               fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
+                               mark_block_used(ctx, extent.e_pblk + i);
+                               mark_block_used(ctx, extent.e_pblk + i);
+                       }
+               }
+
+               /*
+                * Check whether first cluster got marked in previous iteration.
+                */
+               if (ctx->fs->cluster_ratio_bits &&
+                   pb->previous_block &&
+                   (EXT2FS_B2C(ctx->fs, extent.e_pblk) ==
+                    EXT2FS_B2C(ctx->fs, pb->previous_block)))
+                       /* Set blk to the beginning of next cluster. */
+                       blk = EXT2FS_C2B(
+                               ctx->fs,
+                               EXT2FS_B2C(ctx->fs, extent.e_pblk) + 1);
+               else
+                       /* Set blk to the beginning of current cluster. */
+                       blk = EXT2FS_C2B(ctx->fs,
+                                        EXT2FS_B2C(ctx->fs, extent.e_pblk));
+
+               if (blk < extent.e_pblk + extent.e_len) {
+                       mark_blocks_used(ctx, blk,
+                                        extent.e_pblk + extent.e_len - blk);
+                       n = DIV_ROUND_UP(extent.e_pblk + extent.e_len - blk,
+                                        EXT2FS_CLUSTER_RATIO(ctx->fs));
+                       pb->num_blocks += n;
                }
-               if (is_dir && extent.e_len > 0)
-                       pb->last_db_block = blockcnt - 1;
+               pb->last_block = extent.e_lblk + extent.e_len - 1;
                pb->previous_block = extent.e_pblk + extent.e_len - 1;
                start_block = pb->last_block = last_lblk;
                if (is_leaf && !is_dir &&
@@ -3050,7 +3253,7 @@ err:
  * blocks used by that inode.
  */
 static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
-                        char *block_buf)
+                        char *block_buf, const struct ea_quota *ea_ibody_quota)
 {
        ext2_filsys fs = ctx->fs;
        struct process_block_struct pb;
@@ -3061,9 +3264,11 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
        int             extent_fs;
        int             inlinedata_fs;
        __u64           size;
+       struct ea_quota ea_block_quota;
 
        pb.ino = ino;
-       pb.num_blocks = 0;
+       pb.num_blocks = EXT2FS_B2C(ctx->fs,
+                                  ea_ibody_quota ? ea_ibody_quota->blocks : 0);
        pb.last_block = ~0;
        pb.last_init_lblock = -1;
        pb.last_db_block = -1;
@@ -3086,10 +3291,10 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
        extent_fs = ext2fs_has_feature_extents(ctx->fs->super);
        inlinedata_fs = ext2fs_has_feature_inline_data(ctx->fs->super);
 
-       if (check_ext_attr(ctx, pctx, block_buf)) {
+       if (check_ext_attr(ctx, pctx, block_buf, &ea_block_quota)) {
                if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                        goto out;
-               pb.num_blocks++;
+               pb.num_blocks += EXT2FS_B2C(ctx->fs, ea_block_quota.blocks);
        }
 
        if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL))
@@ -3179,12 +3384,15 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
        }
 
        if (ino != quota_type2inum(PRJQUOTA, fs->super) &&
-           (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super))) {
+           (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) &&
+           !(inode->i_flags & EXT4_EA_INODE_FL)) {
                quota_data_add(ctx->qctx, (struct ext2_inode_large *) inode,
                               ino,
                               pb.num_blocks * EXT2_CLUSTER_SIZE(fs->super));
                quota_data_inodes(ctx->qctx, (struct ext2_inode_large *) inode,
-                                 ino, +1);
+                                 ino, (ea_ibody_quota ?
+                                       ea_ibody_quota->inodes : 0) +
+                                               ea_block_quota.inodes + 1);
        }
 
        if (!ext2fs_has_feature_huge_file(fs->super) ||
index 170878c1bf1429861529ead34c327939cde6ce78..09b79c3bb42f04ab5ef629a0a3c88c68e71846e0 100644 (file)
@@ -85,6 +85,39 @@ struct check_dir_struct {
        unsigned long long next_ra_off;
 };
 
+static void update_parents(struct dx_dir_info *dx_dir, int type)
+{
+       struct dx_dirblock_info *dx_db, *dx_parent, *dx_previous;
+       int b;
+
+       for (b = 0, dx_db = dx_dir->dx_block;
+            b < dx_dir->numblocks;
+            b++, dx_db++) {
+               dx_parent = &dx_dir->dx_block[dx_db->parent];
+               if (dx_db->type != type)
+                       continue;
+
+               /*
+                * XXX Make sure dx_parent->min_hash > dx_db->min_hash
+               */
+               if (dx_db->flags & DX_FLAG_FIRST) {
+                       dx_parent->min_hash = dx_db->min_hash;
+                       if (dx_parent->previous) {
+                               dx_previous =
+                                       &dx_dir->dx_block[dx_parent->previous];
+                               dx_previous->node_max_hash =
+                                       dx_parent->min_hash;
+                       }
+               }
+               /*
+                * XXX Make sure dx_parent->max_hash < dx_db->max_hash
+                */
+               if (dx_db->flags & DX_FLAG_LAST) {
+                       dx_parent->max_hash = dx_db->max_hash;
+               }
+       }
+}
+
 void e2fsck_pass2(e2fsck_t ctx)
 {
        struct ext2_super_block *sb = ctx->fs->super;
@@ -182,24 +215,11 @@ void e2fsck_pass2(e2fsck_t ctx)
                 * Find all of the first and last leaf blocks, and
                 * update their parent's min and max hash values
                 */
-               for (b=0, dx_db = dx_dir->dx_block;
-                    b < dx_dir->numblocks;
-                    b++, dx_db++) {
-                       if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
-                           !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
-                               continue;
-                       dx_parent = &dx_dir->dx_block[dx_db->parent];
-                       /*
-                        * XXX Make sure dx_parent->min_hash > dx_db->min_hash
-                        */
-                       if (dx_db->flags & DX_FLAG_FIRST)
-                               dx_parent->min_hash = dx_db->min_hash;
-                       /*
-                        * XXX Make sure dx_parent->max_hash < dx_db->max_hash
-                        */
-                       if (dx_db->flags & DX_FLAG_LAST)
-                               dx_parent->max_hash = dx_db->max_hash;
-               }
+               update_parents(dx_dir, DX_DIRBLOCK_LEAF);
+
+               /* for 3 level htree: update 2 level parent's min
+                * and max hash values */
+               update_parents(dx_dir, DX_DIRBLOCK_NODE);
 
                for (b=0, dx_db = dx_dir->dx_block;
                     b < dx_dir->numblocks;
@@ -642,6 +662,10 @@ static void parse_int_node(ext2_filsys fs,
                        dx_db->flags |= DX_FLAG_REFERENCED;
                        dx_db->parent = db->blockcnt;
                }
+
+               dx_db->previous =
+                       i ? ext2fs_le32_to_cpu(ent[i-1].block & 0x0ffffff) : 0;
+
                if (hash < min_hash)
                        min_hash = hash;
                if (hash > max_hash)
@@ -949,6 +973,14 @@ static int check_dir_block(ext2_filsys fs,
                        return DIRENT_ABORT;
        }
 
+       /* This will allow (at some point in the future) to punch out empty
+        * directory blocks and reduce the space used by a directory that grows
+        * very large and then the files are deleted. For now, all that is
+        * needed is to avoid e2fsck filling in these holes as part of
+        * feature flag. */
+       if (db->blk == 0 && ext2fs_has_feature_largedir(fs->super))
+               return 0;
+
        if (db->blk == 0 && !inline_data_size) {
                if (allocate_dir_block(ctx, db, buf, &cd->pctx))
                        return 0;
@@ -1058,7 +1090,8 @@ inline_read_fail:
                        dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
                        if ((root->reserved_zero ||
                             root->info_length < 8 ||
-                            root->indirect_levels > 1) &&
+                            root->indirect_levels >=
+                            ext2_dir_htree_level(fs)) &&
                            fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
                                clear_htree(ctx, ino);
                                dx_dir->numblocks = 0;
@@ -1811,10 +1844,10 @@ int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
                } else
                        not_fixed++;
        }
-       if (inode.i_dir_acl &&
+       if (inode.i_size_high && !ext2fs_has_feature_largedir(fs->super) &&
            LINUX_S_ISDIR(inode.i_mode)) {
-               if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
-                       inode.i_dir_acl = 0;
+               if (fix_problem(ctx, PR_2_DIR_SIZE_HIGH_ZERO, &pctx)) {
+                       inode.i_size_high = 0;
                        inode_modified++;
                } else
                        not_fixed++;
index 8c101fd2805c9953b11c3d67b9bd251b0e2d3b19..9a491b136b7f605d981de1c0728cbf0df1082afd 100644 (file)
@@ -11,6 +11,7 @@
  * Pass 4 frees the following data structures:
  *     - A bitmap of which inodes are in bad blocks.   (inode_bb_map)
  *     - A bitmap of which inodes are imagic inodes.   (inode_imagic_map)
+ *     - Ref counts for ea_inodes.                     (ea_inode_refs)
  */
 
 #include "config.h"
@@ -38,6 +39,7 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
                               "pass4: disconnect_inode");
        if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
                extra_size = inode->i_extra_isize;
+
        clear_problem_context(&pctx);
        pctx.ino = i;
        pctx.inode = EXT2_INODE(inode);
@@ -85,6 +87,52 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
        return 0;
 }
 
+static void check_ea_inode(e2fsck_t ctx, ext2_ino_t i,
+                          struct ext2_inode_large *inode, __u16 *link_counted)
+{
+       __u64 actual_refs = 0;
+       __u64 ref_count;
+
+       /*
+        * This function is called when link_counted is zero. So this may not
+        * be an xattr inode at all. Return immediately if EA_INODE flag is not
+        * set.
+        */
+       e2fsck_read_inode_full(ctx, i, EXT2_INODE(inode),
+                              EXT2_INODE_SIZE(ctx->fs->super),
+                              "pass4: check_ea_inode");
+       if (!(inode->i_flags & EXT4_EA_INODE_FL))
+               return;
+
+       if (ctx->ea_inode_refs)
+               ea_refcount_fetch(ctx->ea_inode_refs, i, &actual_refs);
+       if (!actual_refs)
+               return;
+
+       /*
+        * There are some attribute references, link_counted is now considered
+        * to be 1.
+        */
+       *link_counted = 1;
+
+       ref_count = ext2fs_get_ea_inode_ref(EXT2_INODE(inode));
+
+       /* Old Lustre-style xattr inodes do not have a stored refcount.
+        * However, their i_ctime and i_atime should be the same.
+        */
+       if (ref_count != actual_refs && inode->i_ctime != inode->i_atime) {
+               struct problem_context pctx;
+
+               clear_problem_context(&pctx);
+               pctx.ino = i;
+               pctx.num = ref_count;
+               pctx.num2 = actual_refs;
+               if (fix_problem(ctx, PR_4_EA_INODE_REF_COUNT, &pctx)) {
+                       ext2fs_set_ea_inode_ref(EXT2_INODE(inode), actual_refs);
+                       e2fsck_write_inode(ctx, i, EXT2_INODE(inode), "pass4");
+               }
+       }
+}
 
 void e2fsck_pass4(e2fsck_t ctx)
 {
@@ -152,6 +200,16 @@ void e2fsck_pass4(e2fsck_t ctx)
                        continue;
                ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
                ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
+
+               if (link_counted == 0) {
+                       /*
+                        * link_counted is expected to be 0 for an ea_inode.
+                        * check_ea_inode() will update link_counted if
+                        * necessary.
+                        */
+                       check_ea_inode(ctx, i, inode, &link_counted);
+               }
+
                if (link_counted == 0) {
                        if (!buf)
                                buf = e2fsck_allocate_memory(ctx,
@@ -197,6 +255,8 @@ void e2fsck_pass4(e2fsck_t ctx)
        ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
        ext2fs_free_inode_bitmap(ctx->inode_bb_map);
        ctx->inode_bb_map = 0;
+       ea_refcount_free(ctx->ea_inode_refs);
+       ctx->ea_inode_refs = 0;
        ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
        ctx->inode_imagic_map = 0;
 errout:
index fb55b7e66c0850ac53269ab63c699c6232aa3a39..ab736496052196fd55970c7bbe1ba53c6bf5390d 100644 (file)
@@ -21,8 +21,6 @@
 #include "e2fsck.h"
 #include "problem.h"
 
-#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-
 static void check_block_bitmaps(e2fsck_t ctx);
 static void check_inode_bitmaps(e2fsck_t ctx);
 static void check_inode_end(e2fsck_t ctx);
index c4c5542950f3561631a4d61245ec8d105424273f..2bb8d4e208c469631e9ca8d65c8237ede4c1f120 100644 (file)
@@ -1150,6 +1150,23 @@ static struct e2fsck_problem problem_table[] = {
          N_("Timestamp(s) on @i %i beyond 2310-04-04 are likely pre-1970.\n"),
          PROMPT_FIX, PR_PREEN_OK | PR_NO_OK },
 
+       /* Inode has illegal extended attribute value inode */
+       { PR_1_ATTR_VALUE_EA_INODE,
+         N_("@i %i has @I @a value @i %N.\n"),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* Inode has invalid extended attribute. EA inode missing
+        * EA_INODE flag. */
+       { PR_1_ATTR_NO_EA_INODE_FL,
+         N_("@i %i has @n @a. EA @i %N missing EA_INODE flag.\n"),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* EA inode for parent inode missing EA_INODE flag. */
+       { PR_1_ATTR_SET_EA_INODE_FL,
+         N_("EA @i %N for parent @i %i missing EA_INODE flag.\n "),
+         PROMPT_FIX, PR_PREEN_OK },
+
+
        /* Pass 1b errors */
 
        /* Pass 1B: Rescan for duplicate/bad blocks */
@@ -1366,9 +1383,9 @@ static struct e2fsck_problem problem_table[] = {
          N_("i_file_acl @F %If, @s zero.\n"),
          PROMPT_CLEAR, 0 },
 
-       /* i_dir_acl should be zero */
-       { PR_2_DIR_ACL_ZERO,
-         N_("i_dir_acl @F %Id, @s zero.\n"),
+       /* i_size_high should be zero */
+       { PR_2_DIR_SIZE_HIGH_ZERO,
+         N_("i_size_high @F %Id, @s zero.\n"),
          PROMPT_CLEAR, 0 },
 
        /* i_frag should be zero */
@@ -1857,6 +1874,10 @@ static struct e2fsck_problem problem_table[] = {
          "They @s the same!\n"),
          PROMPT_NONE, 0 },
 
+       { PR_4_EA_INODE_REF_COUNT,
+         N_("@a @i %i ref count is %N, @s %n. "),
+         PROMPT_FIX, PR_PREEN_OK },
+
        /* Pass 5 errors */
 
        /* Pass 5: Checking group summary information */
index c949547da1053232811f2e6e1c51534e33d81436..49a8c3ad61f603359f79f13f49cb9d4da699e9fa 100644 (file)
@@ -20,7 +20,7 @@ struct problem_context {
        e2_blkcnt_t     blkcount;
        dgrp_t          group;
        __u32           csum1, csum2;
-       __u64   num;
+       __u64           num, num2;
        const char *str;
 };
 
@@ -678,6 +678,17 @@ struct problem_context {
 /* Timestamp(s) on inode beyond 2310-04-04 are likely pre-1970. */
 #define PR_1_EA_TIME_OUT_OF_RANGE              0x010082
 
+/* Inode has illegal EA value inode */
+#define PR_1_ATTR_VALUE_EA_INODE               0x010083
+
+/* Parent inode has invalid EA entry. EA inode does not have
+ * EXT4_EA_INODE_FL flag. Delete EA entry? */
+#define PR_1_ATTR_NO_EA_INODE_FL               0x010085
+
+/* EA inode for parent inode does not have EXT4_EA_INODE_FL flag */
+#define PR_1_ATTR_SET_EA_INODE_FL              0x010086
+
+
 /*
  * Pass 1b errors
  */
@@ -816,8 +827,8 @@ struct problem_context {
 /* i_file_acl should be zero */
 #define PR_2_FILE_ACL_ZERO     0x02000E
 
-/* i_dir_acl should be zero */
-#define PR_2_DIR_ACL_ZERO      0x02000F
+/* i_size_high should be zero */
+#define PR_2_DIR_SIZE_HIGH_ZERO        0x02000F
 
 /* i_frag should be zero */
 #define PR_2_FRAG_ZERO         0x020010
@@ -1123,6 +1134,9 @@ struct problem_context {
 /* Inconsistent inode count information cached */
 #define PR_4_INCONSISTENT_COUNT                0x040004
 
+/* Extended attribute inode ref count wrong */
+#define PR_4_EA_INODE_REF_COUNT                0x040005
+
 /*
  * Pass 5 errors
  */
index 77129e50d1614bf13e6847a51b64aae41beee2f3..486e1f21be6d5c6201120b06922cdfadc0510299 100644 (file)
@@ -603,6 +603,43 @@ static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
        return (struct ext2_dx_entry *) limits;
 }
 
+static int alloc_blocks(ext2_filsys fs,
+                       struct ext2_dx_countlimit **limit,
+                       struct ext2_dx_entry **prev_ent,
+                       struct ext2_dx_entry **next_ent,
+                       int *prev_offset, int *next_offset,
+                       struct out_dir *outdir, int i,
+                       int *prev_count, int *next_count)
+{
+       errcode_t       retval;
+       char            *block_start;
+
+       if (*limit)
+               (*limit)->limit = (*limit)->count =
+                       ext2fs_cpu_to_le16((*limit)->limit);
+       *prev_ent = (struct ext2_dx_entry *) (outdir->buf + *prev_offset);
+       (*prev_ent)->block = ext2fs_cpu_to_le32(outdir->num);
+
+       if (i != 1)
+               (*prev_ent)->hash =
+                       ext2fs_cpu_to_le32(outdir->hashes[i]);
+
+       retval = get_next_block(fs, outdir, &block_start);
+       if (retval)
+               return retval;
+
+       *next_ent = set_int_node(fs, block_start);
+       *limit = (struct ext2_dx_countlimit *)(*next_ent);
+       if (next_offset)
+               *next_offset = ((char *) *next_ent - outdir->buf);
+
+       *next_count = (*limit)->limit;
+       (*prev_offset) += sizeof(struct ext2_dx_entry);
+       (*prev_count)--;
+
+       return 0;
+}
+
 /*
  * This function takes the leaf nodes which have been written in
  * outdir, and populates the root node and any necessary interior nodes.
@@ -612,13 +649,13 @@ static errcode_t calculate_tree(ext2_filsys fs,
                                ext2_ino_t ino,
                                ext2_ino_t parent)
 {
-       struct ext2_dx_root_info        *root_info;
-       struct ext2_dx_entry            *root, *dx_ent = 0;
-       struct ext2_dx_countlimit       *root_limit, *limit;
+       struct ext2_dx_root_info        *root_info;
+       struct ext2_dx_entry            *root, *int_ent, *dx_ent = 0;
+       struct ext2_dx_countlimit       *root_limit, *int_limit, *limit;
        errcode_t                       retval;
        char                            * block_start;
-       int                             i, c1, c2, nblks;
-       int                             limit_offset, root_offset;
+       int                             i, c1, c2, c3, nblks;
+       int                             limit_offset, int_offset, root_offset;
 
        root_info = set_root_node(fs, outdir->buf, ino, parent);
        root_offset = limit_offset = ((char *) root_info - outdir->buf) +
@@ -628,7 +665,7 @@ static errcode_t calculate_tree(ext2_filsys fs,
        nblks = outdir->num;
 
        /* Write out the pointer blocks */
-       if (nblks-1 <= c1) {
+       if (nblks - 1 <= c1) {
                /* Just write out the root block, and we're done */
                root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
                for (i=1; i < nblks; i++) {
@@ -639,31 +676,20 @@ static errcode_t calculate_tree(ext2_filsys fs,
                        root++;
                        c1--;
                }
-       } else {
+       } else if (nblks - 1 <= ext2fs_htree_intnode_maxrecs(fs, c1)) {
                c2 = 0;
-               limit = 0;
+               limit = NULL;
                root_info->indirect_levels = 1;
                for (i=1; i < nblks; i++) {
-                       if (c1 == 0)
+                       if (c2 == 0 && c1 == 0)
                                return ENOSPC;
                        if (c2 == 0) {
-                               if (limit)
-                                       limit->limit = limit->count =
-               ext2fs_cpu_to_le16(limit->limit);
-                               root = (struct ext2_dx_entry *)
-                                       (outdir->buf + root_offset);
-                               root->block = ext2fs_cpu_to_le32(outdir->num);
-                               if (i != 1)
-                                       root->hash =
-                       ext2fs_cpu_to_le32(outdir->hashes[i]);
-                               if ((retval =  get_next_block(fs, outdir,
-                                                             &block_start)))
+                               retval = alloc_blocks(fs, &limit, &root,
+                                                     &dx_ent, &root_offset,
+                                                     NULL, outdir, i, &c1,
+                                                     &c2);
+                               if (retval)
                                        return retval;
-                               dx_ent = set_int_node(fs, block_start);
-                               limit = (struct ext2_dx_countlimit *) dx_ent;
-                               c2 = limit->limit;
-                               root_offset += sizeof(struct ext2_dx_entry);
-                               c1--;
                        }
                        dx_ent->block = ext2fs_cpu_to_le32(i);
                        if (c2 != limit->limit)
@@ -674,6 +700,45 @@ static errcode_t calculate_tree(ext2_filsys fs,
                }
                limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
                limit->limit = ext2fs_cpu_to_le16(limit->limit);
+       } else {
+               c2 = 0;
+               c3 = 0;
+               limit = NULL;
+               int_limit = 0;
+               root_info->indirect_levels = 2;
+               for (i = 1; i < nblks; i++) {
+                       if (c3 == 0 && c2 == 0 && c1 == 0)
+                               return ENOSPC;
+                       if (c3 == 0 && c2 == 0) {
+                               retval = alloc_blocks(fs, &int_limit, &root,
+                                                     &int_ent, &root_offset,
+                                                     &int_offset, outdir, i,
+                                                     &c1, &c2);
+                               if (retval)
+                                       return retval;
+                       }
+                       if (c3 == 0) {
+                               retval = alloc_blocks(fs, &limit, &int_ent,
+                                                     &dx_ent, &int_offset,
+                                                     NULL, outdir, i, &c2,
+                                                     &c3);
+                               if (retval)
+                                       return retval;
+
+                       }
+                       dx_ent->block = ext2fs_cpu_to_le32(i);
+                       if (c3 != limit->limit)
+                               dx_ent->hash =
+                                       ext2fs_cpu_to_le32(outdir->hashes[i]);
+                       dx_ent++;
+                       c3--;
+               }
+               int_limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
+               int_limit->limit = ext2fs_cpu_to_le16(limit->limit);
+
+               limit->count = ext2fs_cpu_to_le16(limit->limit - c3);
+               limit->limit = ext2fs_cpu_to_le16(limit->limit);
+
        }
        root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
        root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
index ad2df960fde4c56dbd518e8cd97b448b38ae6975..7841358a19e225e21b8f6538c135a5f985d608af 100644 (file)
@@ -2726,7 +2726,7 @@ struct ext2_inode {
        __u32   i_block[EXT2_N_BLOCKS]; /* Pointers to blocks */
        __u32   i_version;              /* File version (for NFS) */
        __u32   i_file_acl;             /* File ACL */
-       __u32   i_dir_acl;              /* Directory ACL */
+       __u32   i_size_high;            /* High 32bits of size */
        __u32   i_faddr;                /* Fragment address */
        union {
                struct {
index a6ebf5ab85f01b8a1fd3794de592682b2224608d..900c3930f57cee6f5c88eb5e939aa1e2dff8875b 100644 (file)
@@ -487,7 +487,7 @@ struct ext2_inode {
        __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
        __u32   i_version;      /* File version (for NFS) */
        __u32   i_file_acl;     /* File ACL */
-       __u32   i_dir_acl;      /* Directory ACL */
+       __u32   i_size_high;    /* High 32bits of size */
        __u32   i_faddr;        /* Fragment address */
        union {
                struct {
index bf927b027a23fcbd0b5c411da239486e26c17230..b1ac4c4bb70d31f9bdd7cd9af80ca83d5f0c6981 100644 (file)
@@ -102,7 +102,7 @@ struct ext2_inode {
        __u32  i_block[14]; /* Pointers to blocks */
        __u32  i_version;       /* File version (for NFS) */
        __u32  i_file_acl;      /* File ACL */
-       __u32  i_dir_acl;       /* Directory ACL */
+       __u32  i_size_high;     /* High 32bits of size */
        __u32  i_faddr;         /* Fragment address */
        __u8   l_i_frag;        /* Fragment number */
        __u8   l_i_fsize;       /* Fragment size */
index 8e5bc90a7d50ab96b7947a03e5f7a370ea984a87..eb870113b25803a31e3b2b07b68cde17581bebe7 100644 (file)
@@ -1,10 +1,11 @@
 #ifndef _LINUX_TYPES_H
 #define _LINUX_TYPES_H
 
-#ifndef _MSC_VER
-#error  _MSC_VER not defined
-#endif
+//#ifndef _MSC_VER
+//#error  _MSC_VER not defined
+//#endif
 
+#include <sys/types.h>
 
 typedef unsigned __int8 __u8;
 typedef signed __int8 __s8;
@@ -22,7 +23,11 @@ typedef      signed   __int64        __s64;
 typedef        unsigned __int64        __u64;
 
 
-typedef __u32 ino_t;
+//typedef __u32 ino_t;
+typedef __u32 dev_t;
+typedef __u32 uid_t;
+typedef __u32 gid_t;
 
+#include <stdint.h>
 
 #endif /* LINUX_TYPES_H */
index db6d7d71876677a30538cb2dc69ecf0aff5c35b1..66d7512113375808ee80eddc717e6f1825575120 100644 (file)
@@ -293,7 +293,7 @@ charset.alias: $(srcdir)/config.charset
        $(Q) $(SHELL) $(srcdir)/config.charset '@host@' > t-$@
        $(Q) mv t-$@ $@
 
-check: all
+fullcheck check: all
 
 # We must not install the libintl.h/libintl.a files if we are on a
 # system which has the GNU gettext() function in its C library or in a
diff --git a/lib/Android.bp b/lib/Android.bp
new file mode 100644 (file)
index 0000000..b38d8b1
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2017 The Android Open Source Project
+
+// All the libraries under this directory export their headers as relative
+// paths to this directory (external/e2fsprogs/lib). This is a helper headers
+// only library to allow exporting
+cc_library_headers {
+    name: "libext2-headers",
+    host_supported: true,
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+    export_include_dirs: ["."],
+}
+
+
+subdirs = [
+    "*",
+]
diff --git a/lib/Android.mk b/lib/Android.mk
deleted file mode 100644 (file)
index 5053e7d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/lib/blkid/Android.bp b/lib/blkid/Android.bp
new file mode 100644 (file)
index 0000000..9b385f9
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_blkid",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "cache.c",
+        "dev.c",
+        "devname.c",
+        "devno.c",
+        "getsize.c",
+        "llseek.c",
+        "probe.c",
+        "read.c",
+        "resolve.c",
+        "save.c",
+        "tag.c",
+        "version.c",
+    ],
+    shared_libs: ["libext2_uuid"],
+
+    cflags: [
+        "-W",
+        "-Wall",
+        "-fno-strict-aliasing",
+        "-Wno-macro-redefined",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/blkid/Android.mk b/lib/blkid/Android.mk
deleted file mode 100644 (file)
index 857c4f9..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_blkid_src_files := \
-       cache.c \
-       dev.c \
-       devname.c \
-       devno.c \
-       getsize.c \
-       llseek.c \
-       probe.c \
-       read.c \
-       resolve.c \
-       save.c \
-       tag.c \
-       version.c \
-
-
-libext2_blkid_shared_libraries := libext2_uuid
-
-libext2_blkid_system_shared_libraries := libc
-
-libext2_blkid_static_libraries := libext2_uuid_static
-
-libext2_blkid_system_static_libraries := libc
-
-libext2_blkid_c_includes := external/e2fsprogs/lib
-
-libext2_blkid_cflags := -O2 -g -W -Wall -fno-strict-aliasing
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_blkid_src_files)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_blkid_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(libext2_blkid_shared_libraries)
-LOCAL_C_INCLUDES := $(libext2_blkid_c_includes)
-LOCAL_CFLAGS := $(libext2_blkid_cflags)
-LOCAL_MODULE := libext2_blkid
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_blkid_src_files)
-LOCAL_STATIC_LIBRARIES := $(libext2_blkid_static_libraries) $(libext2_blkid_system_static_libraries)
-LOCAL_C_INCLUDES := $(libext2_blkid_c_includes)
-LOCAL_CFLAGS := $(libext2_blkid_cflags) $(libext2_blkid_cflags_linux) -fno-strict-aliasing
-LOCAL_MODULE := libext2_blkid
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_blkid_src_files)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2_blkid_shared_libraries))
-LOCAL_C_INCLUDES := $(libext2_blkid_c_includes)
-LOCAL_CFLAGS := $(libext2_blkid_cflags)
-LOCAL_MODULE := libext2_blkid-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
index 7f384527ec1e89fd5e44132c82628dd67222fb31..0be2da5cd76494e9447d55c6d09b80bfa802bb9a 100644 (file)
@@ -135,8 +135,9 @@ test_probe: test_probe.in Makefile
        $(Q) cat $(srcdir)/test_probe.in >> test_probe
        $(Q) chmod +x test_probe
 
-check:: all tst_cache tst_dev tst_devname tst_devno tst_getsize tst_probe \
- tst_read tst_resolve tst_save tst_tag test_probe tst_types
+fullcheck check:: all tst_cache tst_dev tst_devname tst_devno \
+ tst_getsize tst_probe tst_read tst_resolve tst_save tst_tag \
+ test_probe tst_types
        ./test_probe
        ./tst_types
 
index 671e781f0d981d85d28872b97bfdacd118662f87..444afdc9e69eada3b2e0930cb70b8bdc716dd82c 100644 (file)
@@ -397,7 +397,7 @@ static int probe_all(blkid_cache cache, int only_if_new)
 {
        FILE *proc;
        char line[1024];
-       char ptname0[128], ptname1[128], *ptname = 0;
+       char ptname0[129], ptname1[129], *ptname = 0;
        char *ptnames[2];
        dev_t devs[2];
        int ma, mi;
index bc006deef917443f5de718bbd67dcd0faf257ca5..91e869e7d3d7ae89c268842240147ad31e0d8eb7 100644 (file)
 /* Define to 1 if you have the <linux/fd.h> header file. */
 #undef HAVE_LINUX_FD_H
 
+/* Define to 1 if you have the <linux/fsmap.h> header file. */
+#undef HAVE_LINUX_FSMAP_H
+
 /* Define to 1 if you have the <linux/loop.h> header file. */
 #undef HAVE_LINUX_LOOP_H
 
 /* Define to 1 if you have the `sync_file_range' function. */
 #undef HAVE_SYNC_FILE_RANGE
 
+/* Define to 1 if you have the 'fsync' function. */
+#undef HAVE_FSYNC
+
 /* Define to 1 if you have the `sysconf' function. */
 #undef HAVE_SYSCONF
 
diff --git a/lib/e2p/Android.bp b/lib/e2p/Android.bp
new file mode 100644 (file)
index 0000000..db51670
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_e2p",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "feature.c",
+        "fgetflags.c",
+        "fsetflags.c",
+        "fgetproject.c",
+        "fsetproject.c",
+        "fgetversion.c",
+        "fsetversion.c",
+        "getflags.c",
+        "getversion.c",
+        "hashstr.c",
+        "iod.c",
+        "ls.c",
+        "mntopts.c",
+        "parse_num.c",
+        "pe.c",
+        "pf.c",
+        "ps.c",
+        "setflags.c",
+        "setversion.c",
+        "uuid.c",
+        "ostype.c",
+        "percent.c",
+    ],
+
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-macro-redefined",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/e2p/Android.mk b/lib/e2p/Android.mk
deleted file mode 100644 (file)
index 8a732c3..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_e2p_src_files := \
-       feature.c \
-       fgetflags.c \
-       fsetflags.c \
-       fgetproject.c \
-       fsetproject.c \
-       fgetversion.c \
-       fsetversion.c \
-       getflags.c \
-       getversion.c \
-       hashstr.c \
-       iod.c \
-       ls.c \
-       mntopts.c \
-       parse_num.c \
-       pe.c \
-       pf.c \
-       ps.c \
-       setflags.c \
-       setversion.c \
-       uuid.c \
-       ostype.c \
-       percent.c
-
-libext2_e2p_c_includes := external/e2fsprogs/lib
-
-libext2_e2p_cflags := -O2 -g -W -Wall
-
-libext2_e2p_system_shared_libraries := libc
-
-libext2_e2p_system_static_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_e2p_src_files)
-LOCAL_C_INCLUDES := $(libext2_e2p_c_includes)
-LOCAL_CFLAGS := $(libext2_e2p_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_e2p_system_shared_libraries)
-LOCAL_MODULE := libext2_e2p
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_e2p_src_files)
-LOCAL_C_INCLUDES := $(libext2_e2p_c_includes)
-LOCAL_CFLAGS := $(libext2_e2p_cflags)
-LOCAL_STATIC_LIBRARIES := $(libext2_e2p_system_static_libraries)
-LOCAL_MODULE := libext2_e2p
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_e2p_src_files)
-LOCAL_C_INCLUDES := $(libext2_e2p_c_includes)
-LOCAL_CFLAGS := $(libext2_e2p_cflags)
-LOCAL_MODULE := libext2_e2p-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
index f3ba1ca5297e7f87e7894a001f24d97988d5533d..58c4e2bf8758704392379a29685394fe6ae6af1f 100644 (file)
@@ -75,7 +75,7 @@ tst_feature: $(srcdir)/feature.c
        $(Q) $(CC) -DTEST_PROGRAM -I$(top_srcdir)/lib -o tst_feature \
                $(srcdir)/feature.c $(ALL_CFLAGS) $(ALL_LDFLAGS)
 
-check::        tst_ostype tst_feature
+fullcheck check::      tst_ostype tst_feature
        ./tst_ostype
        ./tst_feature
 
diff --git a/lib/et/Android.bp b/lib/et/Android.bp
new file mode 100644 (file)
index 0000000..f6ad416
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_com_err",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "error_message.c",
+        "et_name.c",
+        "init_et.c",
+        "com_err.c",
+        "com_right.c",
+    ],
+
+    cflags: [
+        "-W",
+        "-Wall",
+    ],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/et/Android.mk b/lib/et/Android.mk
deleted file mode 100644 (file)
index 8704f4c..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_com_err_src_files := \
-       error_message.c \
-       et_name.c \
-       init_et.c \
-       com_err.c \
-       com_right.c
-
-libext2_com_err_c_includes := external/e2fsprogs/lib
-
-libext2_com_err_cflags := -O2 -g -W -Wall
-
-libext2_com_err_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_com_err_src_files)
-LOCAL_C_INCLUDES := $(libext2_com_err_c_includes)
-LOCAL_CFLAGS := $(libext2_com_err_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := libc
-LOCAL_MODULE := libext2_com_err
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_com_err_src_files)
-LOCAL_C_INCLUDES := $(libext2_com_err_c_includes)
-LOCAL_CFLAGS := $(libext2_com_err_cflags)
-LOCAL_STATIC_LIBRARIES := libc
-LOCAL_MODULE := libext2_com_err
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_com_err_src_files)
-LOCAL_C_INCLUDES := $(libext2_com_err_c_includes)
-LOCAL_CFLAGS := $(libext2_com_err_cflags)
-LOCAL_MODULE := libext2_com_err-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
index 476f1894267340c3396bb1f9775895d746bf3deb..0344679e8e8d97243a5833e4cd7fb265c26afaee 100644 (file)
@@ -137,7 +137,7 @@ uninstall::
                $(DESTDIR)$(pkgconfigdir)/com_err.pc
        $(RM) -rf $(DESTDIR)$(includedir)/et $(DESTDIR)$(datadir)/et
 
-check:: compile_et
+fullcheck check:: compile_et
        for i in $(srcdir)/test_cases/*.et ; do \
                t=`basename $$i | sed -e 's/.et//'`; \
                _ET_DIR_OVERRIDE=$(srcdir) ./compile_et $$i ; \
index fe79122ceb1cc56ccaccdc38ef4b13e1f7717967..5dd8aa6581d6dfa26c1adb42b1accb16c1f3e1fa 100644 (file)
@@ -35,7 +35,9 @@
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#if HAVE_FCNTL
 #include <fcntl.h>
+#endif
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -196,8 +198,10 @@ oops:
  */
 static char *safe_getenv(const char *arg)
 {
+#if !defined(_WIN32)
        if ((getuid() != geteuid()) || (getgid() != getegid()))
                return NULL;
+#endif
 #if HAVE_PRCTL
        if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
                return NULL;
@@ -249,11 +253,13 @@ static void init_debug(void)
                debug_f = fopen("/dev/tty", "a");
        if (debug_f) {
                fd = fileno(debug_f);
+#if defined(HAVE_FCNTL)
                if (fd >= 0) {
                        flags = fcntl(fd, F_GETFD);
                        if (flags >= 0)
                                fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
                }
+#endif
        } else
                debug_mask = DEBUG_INIT;
 
diff --git a/lib/ext2fs/Android.bp b/lib/ext2fs/Android.bp
new file mode 100644 (file)
index 0000000..df07a9b
--- /dev/null
@@ -0,0 +1,134 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2fs",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "ext2_err.c",
+        "alloc.c",
+        "alloc_sb.c",
+        "alloc_stats.c",
+        "alloc_tables.c",
+        "atexit.c",
+        "badblocks.c",
+        "bb_inode.c",
+        "bitmaps.c",
+        "bitops.c",
+        "blkmap64_ba.c",
+        "blkmap64_rb.c",
+        "blknum.c",
+        "block.c",
+        "bmap.c",
+        "check_desc.c",
+        "crc16.c",
+        "crc32c.c",
+        "csum.c",
+        "closefs.c",
+        "dblist.c",
+        "dblist_dir.c",
+        "digest_encode.c",
+        "dirblock.c",
+        "dirhash.c",
+        "dir_iterate.c",
+        "dupfs.c",
+        "expanddir.c",
+        "ext_attr.c",
+        "extent.c",
+        "fallocate.c",
+        "fileio.c",
+        "finddev.c",
+        "flushb.c",
+        "freefs.c",
+        "gen_bitmap.c",
+        "gen_bitmap64.c",
+        "get_num_dirs.c",
+        "get_pathname.c",
+        "getsize.c",
+        "getsectsize.c",
+        "i_block.c",
+        "icount.c",
+        "imager.c",
+        "ind_block.c",
+        "initialize.c",
+        "inline.c",
+        "inline_data.c",
+        "inode.c",
+        "io_manager.c",
+        "ismounted.c",
+        "link.c",
+        "llseek.c",
+        "lookup.c",
+        "mmp.c",
+        "mkdir.c",
+        "mkjournal.c",
+        "namei.c",
+        "native.c",
+        "newdir.c",
+        "openfs.c",
+        "progress.c",
+        "punch.c",
+        "qcow2.c",
+        "rbtree.c",
+        "read_bb.c",
+        "read_bb_file.c",
+        "res_gdt.c",
+        "rw_bitmaps.c",
+        "sha256.c",
+        "sha512.c",
+        "swapfs.c",
+        "symlink.c",
+        "undo_io.c",
+        "unix_io.c",
+        "sparse_io.c",
+        "unlink.c",
+        "valid_blk.c",
+        "version.c",
+        // get rid of this?!
+        "test_io.c",
+    ],
+    shared_libs: [
+        "libsparse",
+    ],
+    whole_static_libs: [
+        "libext2_com_err"
+    ],
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-unused-parameter",
+        "-Wno-macro-redefined",
+    ],
+    target: {
+        host: {
+            shared_libs: ["libz-host"],
+            // Consider removing this library as a whole for the host. It is not
+            // in the android side.
+            whole_static_libs: ["libext2_com_err"],
+        },
+        android: {
+            shared_libs: [
+                "libext2_com_err",
+                "libext2_uuid",
+                "libz"
+            ],
+        },
+        windows: {
+            // include/nonunix is used as an overlay on top of the system
+            // include directory. Some empty header files in include/nonunix
+            // hide the ones in the system include path. This setup doesn't work
+            // unless we pass the include/nonunix as an -isystem flag.
+            // TODO(deymo): Enable windows
+            enabled: false,
+            cflags: [
+                "-Wno-format",
+            //    "-isystem external/e2fsprogs/include/nonunix",
+            ],
+            host_ldlibs: ["-lws2_32"],
+        },
+    },
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/ext2fs/Android.mk b/lib/ext2fs/Android.mk
deleted file mode 100644 (file)
index 356232f..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2fs_src_files := \
-       ext2_err.c \
-       alloc.c \
-       alloc_sb.c \
-       alloc_stats.c \
-       alloc_tables.c \
-       atexit.c \
-       badblocks.c \
-       bb_inode.c \
-       bitmaps.c \
-       bitops.c \
-       blkmap64_ba.c \
-       blkmap64_rb.c \
-       blknum.c \
-       block.c \
-       bmap.c \
-       check_desc.c \
-       crc16.c \
-       crc32c.c \
-       csum.c \
-       closefs.c \
-       dblist.c \
-       dblist_dir.c \
-       digest_encode.c \
-       dirblock.c \
-       dirhash.c \
-       dir_iterate.c \
-       dupfs.c \
-       expanddir.c \
-       ext_attr.c \
-       extent.c \
-       fallocate.c \
-       fileio.c \
-       finddev.c \
-       flushb.c \
-       freefs.c \
-       gen_bitmap.c \
-       gen_bitmap64.c \
-       get_num_dirs.c \
-       get_pathname.c \
-       getsize.c \
-       getsectsize.c \
-       i_block.c \
-       icount.c \
-       imager.c \
-       ind_block.c \
-       initialize.c \
-       inline.c \
-       inline_data.c \
-       inode.c \
-       io_manager.c \
-       ismounted.c \
-       link.c \
-       llseek.c \
-       lookup.c \
-       mmp.c \
-       mkdir.c \
-       mkjournal.c \
-       namei.c \
-       native.c \
-       newdir.c \
-       openfs.c \
-       progress.c \
-       punch.c \
-       qcow2.c \
-       rbtree.c \
-       read_bb.c \
-       read_bb_file.c \
-       res_gdt.c \
-       rw_bitmaps.c \
-       sha256.c \
-       sha512.c \
-       swapfs.c \
-       symlink.c \
-       undo_io.c \
-       unix_io.c \
-       unlink.c \
-       valid_blk.c \
-       version.c
-
-# get rid of this?!
-libext2fs_src_files += test_io.c
-
-libext2fs_shared_libraries := \
-       libext2_com_err \
-       libext2_uuid \
-       libext2_blkid \
-       libext2_e2p
-
-libext2fs_system_shared_libraries := libc
-
-libext2fs_static_libraries := \
-       libext2_com_err \
-       libext2_uuid_static \
-       libext2_blkid \
-       libext2_e2p
-
-libext2fs_system_static_libraries := libc
-
-libext2fs_c_includes := external/e2fsprogs/lib
-
-libext2fs_cflags := -O2 -g -W -Wall
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2fs_src_files)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2fs_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(libext2fs_shared_libraries)
-LOCAL_C_INCLUDES := $(libext2fs_c_includes)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(libext2fs_c_includes)
-LOCAL_CFLAGS := $(libext2fs_cflags)
-LOCAL_MODULE := libext2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2fs_src_files)
-LOCAL_STATIC_LIBRARIES := $(libext2fs_static_libraries) $(libext2fs_system_static_libraries)
-LOCAL_C_INCLUDES := $(libext2fs_c_includes)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(libext2fs_c_includes)
-LOCAL_CFLAGS := $(libext2fs_cflags) $(libext2fs_cflags_linux)
-LOCAL_MODULE := libext2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2fs_src_files)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2fs_shared_libraries))
-LOCAL_C_INCLUDES := $(libext2fs_c_includes)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(libext2fs_c_includes)
-LOCAL_CFLAGS := $(libext2fs_cflags)
-LOCAL_MODULE := libext2fs-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
index 425b85614a6670254eaf2417080cbbdb0ebf401e..b6b0f855ca217c25af3ecdf28a6f3b52814091c2 100644 (file)
@@ -125,6 +125,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
        $(TDB_OBJ) \
        undo_io.o \
        unix_io.o \
+       sparse_io.o \
        unlink.o \
        valid_blk.o \
        version.o \
@@ -212,6 +213,7 @@ SRCS= ext2_err.c \
        $(srcdir)/tst_iscan.c \
        $(srcdir)/undo_io.c \
        $(srcdir)/unix_io.c \
+       $(srcdir)/sparse_io.c \
        $(srcdir)/unlink.c \
        $(srcdir)/valid_blk.c \
        $(srcdir)/version.c \
@@ -521,7 +523,7 @@ mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
        $(Q) $(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG \
                $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS) $(SYSLIBS)
 
-check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
+fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
     tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \
     tst_inline tst_inline_data tst_libext2fs tst_sha256 tst_sha512 \
     tst_digest_encode tst_getsize tst_getsectsize
@@ -1108,6 +1110,12 @@ unix_io.o: $(srcdir)/unix_io.c $(top_builddir)/lib/config.h \
  $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
  $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+sparse_io.o: $(srcdir)/sparse_io.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 unlink.o: $(srcdir)/unlink.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
index f96ac4bf89b1b2b1ef1f20e3b3635d8c49110ffe..3fd921679286cc0410a8032e5a8d9e483ef7c670 100644 (file)
@@ -144,27 +144,38 @@ errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
  * Stupid algorithm --- we now just search forward starting from the
  * goal.  Should put in a smarter one someday....
  */
-errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
-                          ext2fs_block_bitmap map, blk64_t *ret)
+errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal,
+                           ext2fs_block_bitmap map, blk64_t *ret,
+                           struct blk_alloc_ctx *ctx)
 {
        errcode_t retval;
        blk64_t b = 0;
        errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret);
+       errcode_t (*gab2)(ext2_filsys, blk64_t, blk64_t *,
+                         struct blk_alloc_ctx *);
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
-       if (!map && fs->get_alloc_block) {
+       if (!map) {
                /*
                 * In case there are clients out there whose get_alloc_block
                 * handlers call ext2fs_new_block2 with a NULL block map,
                 * temporarily swap out the function pointer so that we don't
                 * end up in an infinite loop.
                 */
-               gab = fs->get_alloc_block;
-               fs->get_alloc_block = NULL;
-               retval = gab(fs, goal, &b);
-               fs->get_alloc_block = gab;
-               goto allocated;
+               if (fs->get_alloc_block2) {
+                       gab2 = fs->get_alloc_block2;
+                       fs->get_alloc_block2 = NULL;
+                       retval = gab2(fs, goal, &b, ctx);
+                       fs->get_alloc_block2 = gab2;
+                       goto allocated;
+               } else if (fs->get_alloc_block) {
+                       gab = fs->get_alloc_block;
+                       fs->get_alloc_block = NULL;
+                       retval = gab(fs, goal, &b);
+                       fs->get_alloc_block = gab;
+                       goto allocated;
+               }
        }
        if (!map)
                map = fs->block_map;
@@ -190,6 +201,12 @@ allocated:
        return 0;
 }
 
+errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
+                          ext2fs_block_bitmap map, blk64_t *ret)
+{
+       return ext2fs_new_block3(fs, goal, map, ret, NULL);
+}
+
 errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
                           ext2fs_block_bitmap map, blk_t *ret)
 {
@@ -205,13 +222,17 @@ errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
  * This function zeros out the allocated block, and updates all of the
  * appropriate filesystem records.
  */
-errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
-                            char *block_buf, blk64_t *ret)
+errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, char *block_buf,
+                             blk64_t *ret, struct blk_alloc_ctx *ctx)
 {
        errcode_t       retval;
        blk64_t         block;
 
-       if (fs->get_alloc_block) {
+       if (fs->get_alloc_block2) {
+               retval = (fs->get_alloc_block2)(fs, goal, &block, ctx);
+               if (retval)
+                       goto fail;
+       } else if (fs->get_alloc_block) {
                retval = (fs->get_alloc_block)(fs, goal, &block);
                if (retval)
                        goto fail;
@@ -222,7 +243,7 @@ errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
                                goto fail;
                }
 
-               retval = ext2fs_new_block2(fs, goal, 0, &block);
+               retval = ext2fs_new_block3(fs, goal, 0, &block, ctx);
                if (retval)
                        goto fail;
        }
@@ -242,15 +263,21 @@ fail:
        return retval;
 }
 
+errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
+                            char *block_buf, blk64_t *ret)
+{
+       return ext2fs_alloc_block3(fs, goal, block_buf, ret, NULL);
+}
+
 errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
                             char *block_buf, blk_t *ret)
 {
        errcode_t retval;
-       blk64_t val;
-       retval = ext2fs_alloc_block2(fs, goal, block_buf, &val);
+       blk64_t ret64, goal64 = goal;
+       retval = ext2fs_alloc_block3(fs, goal64, block_buf, &ret64, NULL);
        if (!retval)
-               *ret = (blk_t) val;
-       return retval;
+               *ret = (blk_t)ret64;
+        return retval;
 }
 
 errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish,
@@ -326,10 +353,11 @@ blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino,
        ext2_extent_handle_t    handle = NULL;
        errcode_t               err;
 
-       if (inode == NULL || ext2fs_inode_data_blocks2(fs, inode) == 0)
-               goto no_blocks;
-
-       if (inode->i_flags & EXT4_INLINE_DATA_FL)
+       /* Make sure data stored in inode->i_block is neither fast symlink nor
+        * inline data.
+        */
+       if (inode == NULL || ext2fs_is_fast_symlink(inode) ||
+           inode->i_flags & EXT4_INLINE_DATA_FL)
                goto no_blocks;
 
        if (inode->i_flags & EXT4_EXTENTS_FL) {
index bc596087d2a7c6dce0bb23b6512080caa53cd44c..505b3c9c396b937118d52537572efdd5d58d8342 100644 (file)
@@ -108,7 +108,7 @@ extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
 extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
                                          blk_t block, int num);
 extern int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap,
-                                         ino_t inode, int num);
+                                         ext2_ino_t inode, int num);
 extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
                                         __u32 bitno);
 extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
index 7e7e29d4b075237dd1e9ca5d19b4911c3ef3e0d2..8d5ddd3fcedc0dbf627f68523c11319697b9d095 100644 (file)
@@ -9,6 +9,7 @@
  * %End-Header%
  */
 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
 #if HAVE_UNISTD_H
@@ -22,6 +23,9 @@
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
+#if HAVE_LINUX_TYPES_H
+#include <linux/types.h>
+#endif
 
 #include "ext2_fs.h"
 #include "ext2fsP.h"
index 29da4ef5fb81d565c33a1126c1e66de64d515601..1ed98aa437fe185c97ebbbc6ec7a6a24779ec35d 100644 (file)
@@ -207,6 +207,7 @@ static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
                             int *ret_flags, int *blocks_alloc,
                             blk64_t *phys_blk)
 {
+       struct blk_alloc_ctx    alloc_ctx;
        struct ext2fs_extent    extent;
        unsigned int            offset;
        errcode_t               retval = 0;
@@ -246,8 +247,12 @@ got_block:
                                     0, block-1, 0, blocks_alloc, &blk64);
                if (retval)
                        blk64 = ext2fs_find_inode_goal(fs, ino, inode, block);
-               retval = ext2fs_alloc_block2(fs, blk64, block_buf,
-                                            &blk64);
+               alloc_ctx.ino = ino;
+               alloc_ctx.inode = inode;
+               alloc_ctx.lblk = extent.e_lblk;
+               alloc_ctx.flags = BLOCK_ALLOC_DATA;
+               retval = ext2fs_alloc_block3(fs, blk64, block_buf, &blk64,
+                                            &alloc_ctx);
                if (retval)
                        return retval;
                blk64 &= ~EXT2FS_CLUSTER_MASK(fs);
@@ -300,9 +305,16 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
        ext2_extent_handle_t handle = 0;
        blk_t addr_per_block;
        blk_t   b, blk32;
+       blk64_t b64;
        char    *buf = 0;
        errcode_t       retval = 0;
        int             blocks_alloc = 0, inode_dirty = 0;
+       struct blk_alloc_ctx alloc_ctx = {
+               .ino    = ino,
+               .inode  = inode,
+               .lblk   = 0,
+               .flags  = BLOCK_ALLOC_DATA,
+       };
 
        if (!(bmap_flags & BMAP_SET))
                *phys_blk = 0;
@@ -359,7 +371,10 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
                            ext2fs_find_inode_goal(fs, ino, inode, block);
 
                if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
-                       retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+                       b64 = b;
+                       retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
+                                                    &alloc_ctx);
+                       b = b64;
                        if (retval)
                                goto done;
                        inode_bmap(inode, block) = b;
@@ -382,7 +397,10 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
                        }
 
                        b = inode_bmap(inode, EXT2_IND_BLOCK-1);
-                       retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+                       b64 = b;
+                       retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
+                                                    &alloc_ctx);
+                       b = b64;
                        if (retval)
                                goto done;
                        inode_bmap(inode, EXT2_IND_BLOCK) = b;
@@ -407,7 +425,10 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
                        }
 
                        b = inode_bmap(inode, EXT2_IND_BLOCK);
-                       retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+                       b64 = b;
+                       retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
+                                                    &alloc_ctx);
+                       b = b64;
                        if (retval)
                                goto done;
                        inode_bmap(inode, EXT2_DIND_BLOCK) = b;
@@ -431,7 +452,10 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
                }
 
                b = inode_bmap(inode, EXT2_DIND_BLOCK);
-               retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+               b64 = b;
+               retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
+                                            &alloc_ctx);
+               b = b64;
                if (retval)
                        goto done;
                inode_bmap(inode, EXT2_TIND_BLOCK) = b;
index e67850fa47afbdae405b4655bf0d427d805ada58..214a099762ee6fa01e65c01a84f4a6c5352eea5d 100644 (file)
@@ -34,7 +34,8 @@ void ext2fs_init_csum_seed(ext2_filsys fs)
 {
        if (ext2fs_has_feature_csum_seed(fs->super))
                fs->csum_seed = fs->super->s_checksum_seed;
-       else if (ext2fs_has_feature_metadata_csum(fs->super))
+       else if (ext2fs_has_feature_metadata_csum(fs->super) ||
+                ext2fs_has_feature_ea_inode(fs->super))
                fs->csum_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid,
                                                 sizeof(fs->super->s_uuid));
 }
index bbb0aaa97bcabdd66ad76b74e3e96dd7c6979869..f2042ed56cf95d80286278158a36b96f47bf24ef 100644 (file)
@@ -29,7 +29,7 @@ struct ext2_ext_attr_entry {
        __u8    e_name_len;     /* length of name */
        __u8    e_name_index;   /* attribute name index */
        __u16   e_value_offs;   /* offset in disk block of value */
-       __u32   e_value_block;  /* disk block attribute is stored on (n/i) */
+       __u32   e_value_inum;   /* inode in which the value is stored */
        __u32   e_value_size;   /* size of attribute value */
        __u32   e_hash;         /* hash value of name and value */
 #if 0
index 27a7d3a79ad16a8191209a8345772412a8b7de6a..3b55000e3a905482f70fd193f657fce17e635d9e 100644 (file)
@@ -398,7 +398,7 @@ struct ext2_inode {
        __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
        __u32   i_generation;   /* File version (for NFS) */
        __u32   i_file_acl;     /* File ACL */
-       __u32   i_size_high;    /* Formerly i_dir_acl, directory ACL */
+       __u32   i_size_high;
        __u32   i_faddr;        /* Fragment address */
        union {
                struct {
@@ -446,7 +446,7 @@ struct ext2_inode_large {
        __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
        __u32   i_generation;   /* File version (for NFS) */
        __u32   i_file_acl;     /* File ACL */
-       __u32   i_size_high;    /* Formerly i_dir_acl, directory ACL */
+       __u32   i_size_high;
        __u32   i_faddr;        /* Fragment address */
        union {
                struct {
@@ -484,8 +484,6 @@ struct ext2_inode_large {
 #define EXT4_EPOCH_BITS 2
 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
 
-#define i_dir_acl      i_size_high
-
 #define i_checksum_lo  osd2.linux2.l_i_checksum_lo
 
 #define inode_includes(size, field)                    \
@@ -923,7 +921,9 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt,                4, ENCRYPT)
 
 #define EXT2_FEATURE_COMPAT_SUPP       0
 #define EXT2_FEATURE_INCOMPAT_SUPP    (EXT2_FEATURE_INCOMPAT_FILETYPE| \
-                                      EXT4_FEATURE_INCOMPAT_MMP)
+                                      EXT4_FEATURE_INCOMPAT_MMP| \
+                                      EXT4_FEATURE_INCOMPAT_LARGEDIR| \
+                                      EXT4_FEATURE_INCOMPAT_EA_INODE)
 #define EXT2_FEATURE_RO_COMPAT_SUPP    (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
                                         EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
                                         EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
index 6b7e97729d44dc6794e3e76e041412798697d1b3..5540900a57f4f21e4f82a19543d48d597fa6dc3d 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef _EXT2FS_EXT2_IO_H
 #define _EXT2FS_EXT2_IO_H
 
+#include <ext2fs/ext2_types.h>
+
 /*
  * ext2_loff_t is defined here since unix_io.c needs it.
  */
@@ -141,6 +143,10 @@ extern errcode_t io_channel_cache_readahead(io_channel io,
 extern io_manager unix_io_manager;
 extern io_manager unixfd_io_manager;
 
+/* sparse_io.c */
+extern io_manager sparse_io_manager;
+extern io_manager sparsefd_io_manager;
+
 /* undo_io.c */
 extern io_manager undo_io_manager;
 extern errcode_t set_undo_io_backing_manager(io_manager manager);
index 8ff49ca669a8bf670c5038c110f0abe95ed10739..a2c8edaa4ac2a743519009c2ea2a3423f69e377c 100644 (file)
@@ -209,6 +209,7 @@ typedef struct ext2_file *ext2_file_t;
 #define EXT2_MKJOURNAL_LAZYINIT        0x0000002 /* don't zero journal inode before use*/
 #define EXT2_MKJOURNAL_NO_MNT_CHECK 0x0000004 /* don't check mount status */
 
+struct blk_alloc_ctx;
 struct opaque_ext2_group_desc;
 
 struct struct_ext2_filsys {
@@ -264,6 +265,8 @@ struct struct_ext2_filsys {
         */
        errcode_t (*get_alloc_block)(ext2_filsys fs, blk64_t goal,
                                     blk64_t *ret);
+       errcode_t (*get_alloc_block2)(ext2_filsys fs, blk64_t goal,
+                                     blk64_t *ret, struct blk_alloc_ctx *ctx);
        void (*block_alloc_stats)(ext2_filsys fs, blk64_t blk, int inuse);
 
        /*
@@ -355,6 +358,17 @@ struct struct_ext2_filsys {
 #define BLOCK_COUNT_TIND       (-3)
 #define BLOCK_COUNT_TRANSLATOR (-4)
 
+#define BLOCK_ALLOC_UNKNOWN    0
+#define BLOCK_ALLOC_DATA       1
+#define BLOCK_ALLOC_METADATA   2
+
+struct blk_alloc_ctx {
+       ext2_ino_t              ino;
+       struct ext2_inode       *inode;
+       blk64_t                 lblk;
+       int                     flags;
+};
+
 #if 0
 /*
  * Flags for ext2fs_move_blocks
@@ -584,11 +598,13 @@ typedef struct ext2_icount *ext2_icount_t;
                                         EXT3_FEATURE_INCOMPAT_RECOVER|\
                                         EXT3_FEATURE_INCOMPAT_EXTENTS|\
                                         EXT4_FEATURE_INCOMPAT_FLEX_BG|\
+                                        EXT4_FEATURE_INCOMPAT_EA_INODE|\
                                         EXT4_LIB_INCOMPAT_MMP|\
                                         EXT4_FEATURE_INCOMPAT_64BIT|\
                                         EXT4_FEATURE_INCOMPAT_INLINE_DATA|\
                                         EXT4_FEATURE_INCOMPAT_ENCRYPT|\
-                                        EXT4_FEATURE_INCOMPAT_CSUM_SEED)
+                                        EXT4_FEATURE_INCOMPAT_CSUM_SEED|\
+                                        EXT4_FEATURE_INCOMPAT_LARGEDIR)
 
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP        (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
                                         EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
@@ -662,6 +678,9 @@ extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
                                  ext2fs_block_bitmap map, blk_t *ret);
 extern errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
                                   ext2fs_block_bitmap map, blk64_t *ret);
+extern errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal,
+                                  ext2fs_block_bitmap map, blk64_t *ret,
+                                  struct blk_alloc_ctx *ctx);
 extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start,
                                        blk_t finish, int num,
                                        ext2fs_block_bitmap map,
@@ -674,6 +693,10 @@ extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
                                    char *block_buf, blk_t *ret);
 extern errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
                                     char *block_buf, blk64_t *ret);
+extern errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal,
+                                    char *block_buf, blk64_t *ret,
+                                    struct blk_alloc_ctx *ctx);
+
 extern void ext2fs_set_alloc_block_callback(ext2_filsys fs,
                                            errcode_t (*func)(ext2_filsys fs,
                                                              blk64_t goal,
@@ -1175,6 +1198,9 @@ extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
 /* ext_attr.c */
 extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry,
                                        void *data);
+extern errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs,
+                                            struct ext2_ext_attr_entry *entry,
+                                            void *data, __u32 *hash);
 extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
 extern errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block,
                                       void *buf);
@@ -1221,6 +1247,12 @@ errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino,
 #define XATTR_HANDLE_FLAG_RAW  0x0001
 errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle,
                              unsigned int *new_flags, unsigned int *old_flags);
+extern void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header,
+                                        struct ext2_ext_attr_entry *end);
+extern __u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode);
+extern void ext2fs_set_ea_inode_hash(struct ext2_inode *inode, __u32 hash);
+extern __u64 ext2fs_get_ea_inode_ref(struct ext2_inode *inode);
+extern void ext2fs_set_ea_inode_ref(struct ext2_inode *inode, __u64 ref_count);
 
 /* extent.c */
 extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
@@ -1581,6 +1613,7 @@ errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name,
 /* symlink.c */
 errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino,
                         const char *name, const char *target);
+int ext2fs_is_fast_symlink(struct ext2_inode *inode);
 
 /* mmp.c */
 errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf);
@@ -1927,6 +1960,23 @@ _INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
        return (blk_t) ext2fs_inode_data_blocks2(fs, inode);
 }
 
+/* htree levels for ext4 */
+#define EXT4_HTREE_LEVEL_COMPAT 2
+#define EXT4_HTREE_LEVEL       3
+
+static inline unsigned int ext2_dir_htree_level(ext2_filsys fs)
+{
+       if (ext2fs_has_feature_largedir(fs->super))
+               return EXT4_HTREE_LEVEL;
+
+       return EXT4_HTREE_LEVEL_COMPAT;
+}
+
+_INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks)
+{
+       return blocks * ((fs->blocksize - 8) / sizeof(struct ext2_dx_entry));
+}
+
 /*
  * This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b)
  */
index 7a9a2d5a39bceb9548177934df9c7d1de06cf67b..f4cc2d0563fa6061317787b36340ba2082934716 100644 (file)
 
 #include "ext2fs.h"
 
+static errcode_t read_ea_inode_hash(ext2_filsys fs, ext2_ino_t ino, __u32 *hash)
+{
+       struct ext2_inode inode;
+       errcode_t retval;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               return retval;
+       *hash = ext2fs_get_ea_inode_hash(&inode);
+       return 0;
+}
+
 #define NAME_HASH_SHIFT 5
 #define VALUE_HASH_SHIFT 16
 
@@ -46,7 +58,7 @@ __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
        }
 
        /* The hash needs to be calculated on the data in little-endian. */
-       if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+       if (entry->e_value_inum == 0 && entry->e_value_size != 0) {
                __u32 *value = (__u32 *)data;
                for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
                         EXT2_EXT_ATTR_PAD_BITS; n; n--) {
@@ -59,6 +71,85 @@ __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
        return hash;
 }
 
+/*
+ * ext2fs_ext_attr_hash_entry2()
+ *
+ * Compute the hash of an extended attribute.
+ * This version of the function supports hashing entries that reference
+ * external inodes (ea_inode feature).
+ */
+errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs,
+                                     struct ext2_ext_attr_entry *entry,
+                                     void *data, __u32 *hash)
+{
+       *hash = ext2fs_ext_attr_hash_entry(entry, data);
+
+       if (entry->e_value_inum) {
+               __u32 ea_inode_hash;
+               errcode_t retval;
+
+               retval = read_ea_inode_hash(fs, entry->e_value_inum,
+                                           &ea_inode_hash);
+               if (retval)
+                       return retval;
+
+               *hash = (*hash << VALUE_HASH_SHIFT) ^
+                       (*hash >> (8*sizeof(*hash) - VALUE_HASH_SHIFT)) ^
+                       ea_inode_hash;
+       }
+       return 0;
+}
+
+#undef NAME_HASH_SHIFT
+#undef VALUE_HASH_SHIFT
+
+#define BLOCK_HASH_SHIFT 16
+
+/* Mirrors ext4_xattr_rehash() implementation in kernel. */
+void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header,
+                                 struct ext2_ext_attr_entry *end)
+{
+       struct ext2_ext_attr_entry *here;
+       __u32 hash = 0;
+
+       here = (struct ext2_ext_attr_entry *)(header+1);
+       while (here < end && !EXT2_EXT_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)) ^
+                      here->e_hash;
+               here = EXT2_EXT_ATTR_NEXT(here);
+       }
+       header->h_hash = hash;
+}
+
+#undef BLOCK_HASH_SHIFT
+
+__u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode)
+{
+       return inode->i_atime;
+}
+
+void ext2fs_set_ea_inode_hash(struct ext2_inode *inode, __u32 hash)
+{
+       inode->i_atime = hash;
+}
+
+__u64 ext2fs_get_ea_inode_ref(struct ext2_inode *inode)
+{
+       return ((__u64)inode->i_ctime << 32) | inode->osd1.linux1.l_i_version;
+}
+
+void ext2fs_set_ea_inode_ref(struct ext2_inode *inode, __u64 ref_count)
+{
+       inode->i_ctime = (__u32)(ref_count >> 32);
+       inode->osd1.linux1.l_i_version = (__u32)ref_count;
+}
+
 static errcode_t check_ext_attr_header(struct ext2_ext_attr_header *header)
 {
        if ((header->h_magic != EXT2_EXT_ATTR_MAGIC_v1 &&
@@ -69,9 +160,6 @@ static errcode_t check_ext_attr_header(struct ext2_ext_attr_header *header)
        return 0;
 }
 
-#undef NAME_HASH_SHIFT
-#undef VALUE_HASH_SHIFT
-
 errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block, void *buf,
                                ext2_ino_t inum)
 {
@@ -207,17 +295,19 @@ errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
 struct ext2_xattr {
        char *name;
        void *value;
-       size_t value_len;
+       unsigned int value_len;
+       ext2_ino_t ea_ino;
 };
 
 struct ext2_xattr_handle {
        errcode_t magic;
        ext2_filsys fs;
        struct ext2_xattr *attrs;
-       size_t length, count;
+       int capacity;
+       int count;
+       int ibody_count;
        ext2_ino_t ino;
        unsigned int flags;
-       int dirty;
 };
 
 static errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
@@ -226,14 +316,14 @@ static errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
        struct ext2_xattr *new_attrs;
        errcode_t err;
 
-       err = ext2fs_get_arrayzero(h->length + expandby,
+       err = ext2fs_get_arrayzero(h->capacity + expandby,
                                   sizeof(struct ext2_xattr), &new_attrs);
        if (err)
                return err;
 
-       memcpy(new_attrs, h->attrs, h->length * sizeof(struct ext2_xattr));
+       memcpy(new_attrs, h->attrs, h->capacity * sizeof(struct ext2_xattr));
        ext2fs_free_mem(&h->attrs);
-       h->length += expandby;
+       h->capacity += expandby;
        h->attrs = new_attrs;
 
        return 0;
@@ -256,44 +346,6 @@ static struct ea_name_index ea_names[] = {
        {0, NULL},
 };
 
-static int find_ea_index(char *fullname, char **name, int *index);
-
-/* Push empty attributes to the end and inlinedata to the front. */
-static int attr_compare(const void *a, const void *b)
-{
-       const struct ext2_xattr *xa = a, *xb = b;
-       char *xa_suffix, *xb_suffix;
-       int xa_idx, xb_idx;
-       int cmp;
-
-       if (xa->name == NULL)
-               return +1;
-       else if (xb->name == NULL)
-               return -1;
-       else if (!strcmp(xa->name, "system.data"))
-               return -1;
-       else if (!strcmp(xb->name, "system.data"))
-               return +1;
-
-       /*
-        * Duplicate the kernel's sorting algorithm because xattr blocks
-        * require sorted keys.
-        */
-       xa_suffix = xa->name;
-       xb_suffix = xb->name;
-       xa_idx = xb_idx = 0;
-       find_ea_index(xa->name, &xa_suffix, &xa_idx);
-       find_ea_index(xb->name, &xb_suffix, &xb_idx);
-       cmp = xa_idx - xb_idx;
-       if (cmp)
-               return cmp;
-       cmp = strlen(xa_suffix) - strlen(xb_suffix);
-       if (cmp)
-               return cmp;
-       cmp = strcmp(xa_suffix, xb_suffix);
-       return cmp;
-}
-
 static const char *find_ea_prefix(int index)
 {
        struct ea_name_index *e;
@@ -305,7 +357,7 @@ static const char *find_ea_prefix(int index)
        return NULL;
 }
 
-static int find_ea_index(char *fullname, char **name, int *index)
+static int find_ea_index(const char *fullname, char **name, int *index)
 {
        struct ea_name_index *e;
 
@@ -581,27 +633,21 @@ static errcode_t convert_disk_buffer_to_posix_acl(const void *value, size_t size
        return 0;
 }
 
-
-static errcode_t write_xattrs_to_buffer(struct ext2_xattr_handle *handle,
-                                       struct ext2_xattr **pos,
-                                       void *entries_start,
-                                       unsigned int storage_size,
-                                       unsigned int value_offset_correction,
-                                       int write_hash)
+static errcode_t
+write_xattrs_to_buffer(ext2_filsys fs, struct ext2_xattr *attrs, int count,
+                      void *entries_start, unsigned int storage_size,
+                      unsigned int value_offset_correction, int write_hash)
 {
-       struct ext2_xattr *x = *pos;
+       struct ext2_xattr *x;
        struct ext2_ext_attr_entry *e = entries_start;
-       char *end = (char *) entries_start + storage_size;
+       void *end = entries_start + storage_size;
        char *shortname;
        unsigned int entry_size, value_size;
        int idx, ret;
+       errcode_t err;
 
        memset(entries_start, 0, storage_size);
-       /* For all remaining x...  */
-       for (; x < handle->attrs + handle->length; x++) {
-               if (!x->name)
-                       continue;
-
+       for (x = attrs; x < attrs + count; x++) {
                /* Calculate index and shortname position */
                shortname = x->name;
                ret = find_ea_index(x->name, &shortname, &idx);
@@ -613,43 +659,43 @@ static errcode_t write_xattrs_to_buffer(struct ext2_xattr_handle *handle,
                value_size = ((x->value_len + EXT2_EXT_ATTR_PAD - 1) /
                              EXT2_EXT_ATTR_PAD) * EXT2_EXT_ATTR_PAD;
 
-               /*
-                * Would entry collide with value?
-                * Note that we must leave sufficient room for a (u32)0 to
-                * mark the end of the entries.
-                */
-               if ((char *)e + entry_size + sizeof(__u32) > end - value_size)
-                       break;
-
                /* Fill out e appropriately */
                e->e_name_len = strlen(shortname);
                e->e_name_index = (ret ? idx : 0);
-               e->e_value_offs = end - value_size - (char *)entries_start +
-                               value_offset_correction;
-               e->e_value_block = 0;
+
                e->e_value_size = x->value_len;
+               e->e_value_inum = x->ea_ino;
 
-               /* Store name and value */
-               end -= value_size;
+               /* Store name */
                memcpy((char *)e + sizeof(*e), shortname, e->e_name_len);
-               memcpy(end, x->value, e->e_value_size);
+               if (x->ea_ino) {
+                       e->e_value_offs = 0;
+               } else {
+                       end -= value_size;
+                       e->e_value_offs = end - entries_start +
+                                                       value_offset_correction;
+                       memcpy(end, x->value, e->e_value_size);
+               }
 
-               if (write_hash)
-                       e->e_hash = ext2fs_ext_attr_hash_entry(e, end);
-               else
+               if (write_hash || x->ea_ino) {
+                       err = ext2fs_ext_attr_hash_entry2(fs, e,
+                                                         x->ea_ino ? 0 : end,
+                                                         &e->e_hash);
+                       if (err)
+                               return err;
+               } else
                        e->e_hash = 0;
 
                e = EXT2_EXT_ATTR_NEXT(e);
                *(__u32 *)e = 0;
        }
-       *pos = x;
-
        return 0;
 }
 
 errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
 {
-       struct ext2_xattr *x;
+       ext2_filsys fs = handle->fs;
+       const int inode_size = EXT2_INODE_SIZE(fs->super);
        struct ext2_inode_large *inode;
        char *start, *block_buf = NULL;
        struct ext2_ext_attr_header *header;
@@ -660,24 +706,23 @@ errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
        errcode_t err;
 
        EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
-       i = EXT2_INODE_SIZE(handle->fs->super);
+       i = inode_size;
        if (i < sizeof(*inode))
                i = sizeof(*inode);
        err = ext2fs_get_memzero(i, &inode);
        if (err)
                return err;
 
-       err = ext2fs_read_inode_full(handle->fs, handle->ino,
-                                    (struct ext2_inode *)inode,
-                                    EXT2_INODE_SIZE(handle->fs->super));
+       err = ext2fs_read_inode_full(fs, handle->ino, EXT2_INODE(inode),
+                                    inode_size);
        if (err)
                goto out;
 
        /* If extra_isize isn't set, we need to set it now */
        if (inode->i_extra_isize == 0 &&
-           EXT2_INODE_SIZE(handle->fs->super) > EXT2_GOOD_OLD_INODE_SIZE) {
+           inode_size > EXT2_GOOD_OLD_INODE_SIZE) {
                char *p = (char *)inode;
-               size_t extra = handle->fs->super->s_want_extra_isize;
+               size_t extra = fs->super->s_want_extra_isize;
 
                if (extra == 0)
                        extra = sizeof(__u32);
@@ -689,58 +734,45 @@ errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
                goto out;
        }
 
-       /*
-        * Force the inlinedata attr to the front and the empty entries
-        * to the end.
-        */
-       x = handle->attrs;
-       qsort(x, handle->length, sizeof(struct ext2_xattr), attr_compare);
-
        /* Does the inode have space for EA? */
        if (inode->i_extra_isize < sizeof(inode->i_extra_isize) ||
-           EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
-                                                 inode->i_extra_isize +
-                                                 sizeof(__u32))
+           inode_size <= EXT2_GOOD_OLD_INODE_SIZE + inode->i_extra_isize +
+                                                               sizeof(__u32))
                goto write_ea_block;
 
        /* Write the inode EA */
        ea_inode_magic = EXT2_EXT_ATTR_MAGIC;
        memcpy(((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
               inode->i_extra_isize, &ea_inode_magic, sizeof(__u32));
-       storage_size = EXT2_INODE_SIZE(handle->fs->super) -
-               EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
-               sizeof(__u32);
+       storage_size = inode_size - EXT2_GOOD_OLD_INODE_SIZE -
+                               inode->i_extra_isize - sizeof(__u32);
        start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
-               inode->i_extra_isize + sizeof(__u32);
+                               inode->i_extra_isize + sizeof(__u32);
 
-       err = write_xattrs_to_buffer(handle, &x, start, storage_size, 0, 0);
+       err = write_xattrs_to_buffer(fs, handle->attrs, handle->ibody_count,
+                                    start, storage_size, 0, 0);
        if (err)
                goto out;
-
 write_ea_block:
        /* Are we done? */
-       if (x >= handle->attrs + handle->count)
+       if (handle->ibody_count == handle->count &&
+           !ext2fs_file_acl_block(fs, EXT2_INODE(inode)))
                goto skip_ea_block;
 
        /* Write the EA block */
-       err = ext2fs_get_memzero(handle->fs->blocksize, &block_buf);
+       err = ext2fs_get_memzero(fs->blocksize, &block_buf);
        if (err)
                goto out;
 
-       storage_size = handle->fs->blocksize -
-               sizeof(struct ext2_ext_attr_header);
+       storage_size = fs->blocksize - sizeof(struct ext2_ext_attr_header);
        start = block_buf + sizeof(struct ext2_ext_attr_header);
 
-       err = write_xattrs_to_buffer(handle, &x, start, storage_size,
-                                    start - block_buf, 1);
+       err = write_xattrs_to_buffer(fs, handle->attrs + handle->ibody_count,
+                                    handle->count - handle->ibody_count, start,
+                                    storage_size, start - block_buf, 1);
        if (err)
                goto out2;
 
-       if (x < handle->attrs + handle->length) {
-               err = EXT2_ET_EA_NO_SPACE;
-               goto out2;
-       }
-
        /* Write a header on the EA block */
        header = (struct ext2_ext_attr_header *) block_buf;
        header->h_magic = EXT2_EXT_ATTR_MAGIC;
@@ -748,31 +780,28 @@ write_ea_block:
        header->h_blocks = 1;
 
        /* Get a new block for writing */
-       err = prep_ea_block_for_write(handle->fs, handle->ino, inode);
+       err = prep_ea_block_for_write(fs, handle->ino, inode);
        if (err)
                goto out2;
 
        /* Finally, write the new EA block */
-       blk = ext2fs_file_acl_block(handle->fs,
-                                   (struct ext2_inode *)inode);
-       err = ext2fs_write_ext_attr3(handle->fs, blk, block_buf,
-                                    handle->ino);
+       blk = ext2fs_file_acl_block(fs, EXT2_INODE(inode));
+       err = ext2fs_write_ext_attr3(fs, blk, block_buf, handle->ino);
        if (err)
                goto out2;
 
 skip_ea_block:
-       blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
+       blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
        if (!block_buf && blk) {
                /* xattrs shrunk, free the block */
-               err = ext2fs_free_ext_attr(handle->fs, handle->ino, inode);
+               err = ext2fs_free_ext_attr(fs, handle->ino, inode);
                if (err)
                        goto out;
        }
 
        /* Write the inode */
-       err = ext2fs_write_inode_full(handle->fs, handle->ino,
-                                     (struct ext2_inode *)inode,
-                                     EXT2_INODE_SIZE(handle->fs->super));
+       err = ext2fs_write_inode_full(fs, handle->ino, EXT2_INODE(inode),
+                                     inode_size);
        if (err)
                goto out2;
 
@@ -780,15 +809,14 @@ out2:
        ext2fs_free_mem(&block_buf);
 out:
        ext2fs_free_mem(&inode);
-       handle->dirty = 0;
        return err;
 }
 
 static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
+                                        struct ext2_inode_large *inode,
                                         struct ext2_ext_attr_entry *entries,
                                         unsigned int storage_size,
-                                        char *value_start,
-                                        size_t *nr_read)
+                                        char *value_start)
 {
        struct ext2_xattr *x;
        struct ext2_ext_attr_entry *entry, *end;
@@ -798,10 +826,6 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
        unsigned int values_size = storage_size +
                        ((char *)entries - value_start);
 
-       x = handle->attrs;
-       while (x->name)
-               x++;
-
        /* find the end */
        end = entries;
        remain = storage_size;
@@ -824,48 +848,23 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
        remain = storage_size;
        while (remain >= sizeof(struct ext2_ext_attr_entry) &&
               !EXT2_EXT_IS_LAST_ENTRY(entry)) {
-               __u32 hash;
-
-               /* header eats this space */
-               remain -= sizeof(struct ext2_ext_attr_entry);
-
-               /* attribute len eats this space */
-               remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
-
-               /* check value size */
-               if (entry->e_value_size > remain)
-                       return EXT2_ET_EA_BAD_VALUE_SIZE;
-
-               if (entry->e_value_offs + entry->e_value_size > values_size)
-                       return EXT2_ET_EA_BAD_VALUE_OFFSET;
-
-               if (entry->e_value_size > 0 &&
-                   value_start + entry->e_value_offs <
-                   (char *)end + sizeof(__u32))
-                       return EXT2_ET_EA_BAD_VALUE_OFFSET;
-
-               /* e_value_block must be 0 in inode's ea */
-               if (entry->e_value_block != 0)
-                       return EXT2_ET_BAD_EA_BLOCK_NUM;
-
-               hash = ext2fs_ext_attr_hash_entry(entry, value_start +
-                                                        entry->e_value_offs);
-
-               /* e_hash may be 0 in older inode's ea */
-               if (entry->e_hash != 0 && entry->e_hash != hash)
-                       return EXT2_ET_BAD_EA_HASH;
-
-               remain -= entry->e_value_size;
 
                /* Allocate space for more attrs? */
-               if (x == handle->attrs + handle->length) {
+               if (handle->count == handle->capacity) {
                        err = ext2fs_xattrs_expand(handle, 4);
                        if (err)
                                return err;
-                       x = handle->attrs + handle->length - 4;
                }
 
-               /* Extract name/value */
+               x = handle->attrs + handle->count;
+
+               /* header eats this space */
+               remain -= sizeof(struct ext2_ext_attr_entry);
+
+               /* attribute len eats this space */
+               remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
+
+               /* Extract name */
                prefix = find_ea_prefix(entry->e_name_index);
                prefix_len = (prefix ? strlen(prefix) : 0);
                err = ext2fs_get_memzero(entry->e_name_len + prefix_len + 1,
@@ -879,14 +878,90 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
                               (char *)entry + sizeof(*entry),
                               entry->e_name_len);
 
-               err = ext2fs_get_mem(entry->e_value_size, &x->value);
-               if (err)
-                       return err;
+               /* Check & copy value */
+               if (!ext2fs_has_feature_ea_inode(handle->fs->super) &&
+                   entry->e_value_inum != 0)
+                       return EXT2_ET_BAD_EA_BLOCK_NUM;
+
+               if (entry->e_value_inum == 0) {
+                       if (entry->e_value_size > remain)
+                               return EXT2_ET_EA_BAD_VALUE_SIZE;
+
+                       if (entry->e_value_offs + entry->e_value_size > values_size)
+                               return EXT2_ET_EA_BAD_VALUE_OFFSET;
+
+                       if (entry->e_value_size > 0 &&
+                           value_start + entry->e_value_offs <
+                           (char *)end + sizeof(__u32))
+                               return EXT2_ET_EA_BAD_VALUE_OFFSET;
+
+                       remain -= entry->e_value_size;
+
+                       err = ext2fs_get_mem(entry->e_value_size, &x->value);
+                       if (err)
+                               return err;
+                       memcpy(x->value, value_start + entry->e_value_offs,
+                              entry->e_value_size);
+               } else {
+                       ext2_file_t ea_file;
+
+                       if (entry->e_value_offs != 0)
+                               return EXT2_ET_EA_BAD_VALUE_OFFSET;
+
+                       if (entry->e_value_size > (64 * 1024))
+                               return EXT2_ET_EA_BAD_VALUE_SIZE;
+
+                       err = ext2fs_get_mem(entry->e_value_size, &x->value);
+                       if (err)
+                               return err;
+
+                       err = ext2fs_file_open(handle->fs, entry->e_value_inum,
+                                              0, &ea_file);
+                       if (err)
+                               return err;
+
+                       if (ext2fs_file_get_size(ea_file) !=
+                           entry->e_value_size)
+                               err = EXT2_ET_EA_BAD_VALUE_SIZE;
+                       else
+                               err = ext2fs_file_read(ea_file, x->value,
+                                                      entry->e_value_size, 0);
+                       ext2fs_file_close(ea_file);
+                       if (err)
+                               return err;
+               }
+
+               x->ea_ino = entry->e_value_inum;
                x->value_len = entry->e_value_size;
-               memcpy(x->value, value_start + entry->e_value_offs,
-                      entry->e_value_size);
-               x++;
-               (*nr_read)++;
+
+               /* e_hash may be 0 in older inode's ea */
+               if (entry->e_hash != 0) {
+                       __u32 hash;
+                       void *data = (entry->e_value_inum != 0) ?
+                                       0 : value_start + entry->e_value_offs;
+
+                       err = ext2fs_ext_attr_hash_entry2(handle->fs, entry,
+                                                         data, &hash);
+                       if (err)
+                               return err;
+                       if (entry->e_hash != hash) {
+                               struct ext2_inode child;
+
+                               /* Check whether this is an old Lustre-style
+                                * ea_inode reference.
+                                */
+                               err = ext2fs_read_inode(handle->fs,
+                                                       entry->e_value_inum,
+                                                       &child);
+                               if (err)
+                                       return err;
+                               if (child.i_mtime != handle->ino ||
+                                   child.i_generation != inode->i_generation)
+                                       return EXT2_ET_BAD_EA_HASH;
+                       }
+               }
+
+               handle->count++;
                entry = EXT2_EXT_ATTR_NEXT(entry);
        }
 
@@ -898,13 +973,14 @@ static void xattrs_free_keys(struct ext2_xattr_handle *h)
        struct ext2_xattr *a = h->attrs;
        size_t i;
 
-       for (i = 0; i < h->length; i++) {
+       for (i = 0; i < h->capacity; i++) {
                if (a[i].name)
                        ext2fs_free_mem(&a[i].name);
                if (a[i].value)
                        ext2fs_free_mem(&a[i].value);
        }
        h->count = 0;
+       h->ibody_count = 0;
 }
 
 errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
@@ -955,11 +1031,13 @@ errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
                start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
                        inode->i_extra_isize + sizeof(__u32);
 
-               err = read_xattrs_from_buffer(handle,
-                       (struct ext2_ext_attr_entry *) start, storage_size,
-                                             start, &handle->count);
+               err = read_xattrs_from_buffer(handle, inode,
+                                       (struct ext2_ext_attr_entry *) start,
+                                       storage_size, start);
                if (err)
                        goto out;
+
+               handle->ibody_count = handle->count;
        }
 
 read_ea_block:
@@ -992,9 +1070,9 @@ read_ea_block:
                storage_size = handle->fs->blocksize -
                        sizeof(struct ext2_ext_attr_header);
                start = block_buf + sizeof(struct ext2_ext_attr_header);
-               err = read_xattrs_from_buffer(handle,
-                       (struct ext2_ext_attr_entry *) start, storage_size,
-                                             block_buf, &handle->count);
+               err = read_xattrs_from_buffer(handle, inode,
+                                       (struct ext2_ext_attr_entry *) start,
+                                       storage_size, block_buf);
                if (err)
                        goto out3;
 
@@ -1018,20 +1096,20 @@ errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
                                void *data)
 {
        struct ext2_xattr *x;
+       int dirty = 0;
        int ret;
 
        EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
-       for (x = h->attrs; x < h->attrs + h->length; x++) {
-               if (!x->name)
-                       continue;
-
+       for (x = h->attrs; x < h->attrs + h->count; x++) {
                ret = func(x->name, x->value, x->value_len, data);
                if (ret & XATTR_CHANGED)
-                       h->dirty = 1;
+                       dirty = 1;
                if (ret & XATTR_ABORT)
-                       return 0;
+                       break;
        }
 
+       if (dirty)
+               return ext2fs_xattrs_write(h);
        return 0;
 }
 
@@ -1043,8 +1121,8 @@ errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
        errcode_t err;
 
        EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
-       for (x = h->attrs; x < h->attrs + h->length; x++) {
-               if (!x->name || strcmp(x->name, key))
+       for (x = h->attrs; x < h->attrs + h->count; x++) {
+               if (strcmp(x->name, key))
                        continue;
 
                if (!(h->flags & XATTR_HANDLE_FLAG_RAW) &&
@@ -1107,7 +1185,7 @@ errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino,
                        inode->i_extra_isize + sizeof(__u32);
                entry = (struct ext2_ext_attr_entry *) start;
                while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
-                       if (!entry->e_value_block && entry->e_value_size) {
+                       if (!entry->e_value_inum && entry->e_value_size) {
                                unsigned int offs = entry->e_value_offs;
                                if (offs < minoff)
                                        minoff = offs;
@@ -1127,101 +1205,446 @@ out:
        return err;
 }
 
-errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
-                          const char *key,
+static errcode_t xattr_create_ea_inode(ext2_filsys fs, const void *value,
+                                      size_t value_len, ext2_ino_t *ea_ino)
+{
+       struct ext2_inode inode;
+       ext2_ino_t ino;
+       ext2_file_t file;
+       __u32 hash;
+       errcode_t ret;
+
+       ret = ext2fs_new_inode(fs, 0, 0, 0, &ino);
+       if (ret)
+               return ret;
+
+       memset(&inode, 0, sizeof(inode));
+       inode.i_flags |= EXT4_EA_INODE_FL;
+       if (ext2fs_has_feature_extents(fs->super))
+               inode.i_flags |= EXT4_EXTENTS_FL;
+       inode.i_size = 0;
+       inode.i_mode = LINUX_S_IFREG | 0600;
+       inode.i_links_count = 1;
+       ret = ext2fs_write_new_inode(fs, ino, &inode);
+       if (ret)
+               return ret;
+       /*
+        * ref_count and hash utilize inode's i_*time fields.
+        * ext2fs_write_new_inode() call above initializes these fields with
+        * current time. That's why ref count and hash updates are done
+        * separately below.
+        */
+       ext2fs_set_ea_inode_ref(&inode, 1);
+       hash = ext2fs_crc32c_le(fs->csum_seed, value, value_len);
+       ext2fs_set_ea_inode_hash(&inode, hash);
+
+       ret = ext2fs_write_inode(fs, ino, &inode);
+       if (ret)
+               return ret;
+
+       ret = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file);
+       if (ret)
+               return ret;
+       ret = ext2fs_file_write(file, value, value_len, NULL);
+       ext2fs_file_close(file);
+       if (ret)
+               return ret;
+
+       ext2fs_inode_alloc_stats2(fs, ino, 1 /* inuse */, 0 /* isdir */);
+
+       *ea_ino = ino;
+       return 0;
+}
+
+static errcode_t xattr_inode_dec_ref(ext2_filsys fs, ext2_ino_t ino)
+{
+       struct ext2_inode_large inode;
+       __u64 ref_count;
+       errcode_t ret;
+
+       ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
+                                    sizeof(inode));
+       if (ret)
+               goto out;
+
+       ref_count = ext2fs_get_ea_inode_ref(EXT2_INODE(&inode));
+       ref_count--;
+       ext2fs_set_ea_inode_ref(EXT2_INODE(&inode), ref_count);
+
+       if (ref_count)
+               goto write_out;
+
+       inode.i_links_count = 0;
+       inode.i_dtime = fs->now ? fs->now : time(0);
+
+       ret = ext2fs_free_ext_attr(fs, ino, &inode);
+       if (ret)
+               goto write_out;
+
+       if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) {
+               ret = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL,
+                                  0, ~0ULL);
+               if (ret)
+                       goto out;
+       }
+
+       ext2fs_inode_alloc_stats2(fs, ino, -1 /* inuse */, 0 /* is_dir */);
+
+write_out:
+       ret = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
+                                     sizeof(inode));
+out:
+       return ret;
+}
+
+static errcode_t xattr_update_entry(ext2_filsys fs, struct ext2_xattr *x,
+                                   const char *name, const void *value,
+                                   size_t value_len, int in_inode)
+{
+       ext2_ino_t ea_ino = 0;
+       void *new_value = NULL;
+       char *new_name = NULL;
+       int name_len;
+       errcode_t ret;
+
+       if (!x->name) {
+               name_len = strlen(name);
+               ret = ext2fs_get_mem(name_len + 1, &new_name);
+               if (ret)
+                       goto fail;
+               memcpy(new_name, name, name_len + 1);
+       }
+
+       ret = ext2fs_get_mem(value_len, &new_value);
+       if (ret)
+               goto fail;
+       memcpy(new_value, value, value_len);
+
+       if (in_inode) {
+               ret = xattr_create_ea_inode(fs, value, value_len, &ea_ino);
+               if (ret)
+                       goto fail;
+       }
+
+       if (x->ea_ino) {
+               ret = xattr_inode_dec_ref(fs, x->ea_ino);
+               if (ret)
+                       goto fail;
+       }
+
+       if (!x->name)
+               x->name = new_name;
+
+       if (x->value)
+               ext2fs_free_mem(&x->value);
+       x->value = new_value;
+       x->value_len = value_len;
+       x->ea_ino = ea_ino;
+       return 0;
+fail:
+       if (new_name)
+               ext2fs_free_mem(&new_name);
+       if (new_value)
+               ext2fs_free_mem(&new_value);
+       if (ea_ino)
+               xattr_inode_dec_ref(fs, ea_ino);
+       return ret;
+}
+
+static int xattr_find_position(struct ext2_xattr *attrs, int count,
+                              const char *name)
+{
+       struct ext2_xattr *x;
+       int i;
+       char *shortname, *x_shortname;
+       int name_idx, x_name_idx;
+       int shortname_len, x_shortname_len;
+
+       find_ea_index(name, &shortname, &name_idx);
+       shortname_len = strlen(shortname);
+
+       for (i = 0, x = attrs; i < count; i++, x++) {
+               find_ea_index(x->name, &x_shortname, &x_name_idx);
+               if (name_idx < x_name_idx)
+                       break;
+               if (name_idx > x_name_idx)
+                       continue;
+
+               x_shortname_len = strlen(x_shortname);
+               if (shortname_len < x_shortname_len)
+                       break;
+               if (shortname_len > x_shortname_len)
+                       continue;
+
+               if (memcmp(shortname, x_shortname, shortname_len) <= 0)
+                       break;
+       }
+       return i;
+}
+
+errcode_t xattr_array_update(struct ext2_xattr_handle *h, const char *name,
+                       const void *value, size_t value_len, int ibody_free,
+                       int block_free, int old_idx, int in_inode)
+{
+       struct ext2_xattr tmp;
+       int add_to_ibody;
+       int needed;
+       int name_len, name_idx;
+       char *shortname;
+       int new_idx;
+       int ret;
+
+       find_ea_index(name, &shortname, &name_idx);
+       name_len = strlen(shortname);
+
+       needed = EXT2_EXT_ATTR_LEN(name_len);
+       if (!in_inode)
+               needed += EXT2_EXT_ATTR_SIZE(value_len);
+
+       if (old_idx >= 0 && old_idx < h->ibody_count) {
+               ibody_free += EXT2_EXT_ATTR_LEN(name_len);
+               if (!h->attrs[old_idx].ea_ino)
+                       ibody_free += EXT2_EXT_ATTR_SIZE(
+                                               h->attrs[old_idx].value_len);
+       }
+
+       if (needed <= ibody_free) {
+               if (old_idx < 0) {
+                       new_idx = h->ibody_count;
+                       add_to_ibody = 1;
+                       goto add_new;
+               }
+
+               /* Update the existing entry. */
+               ret = xattr_update_entry(h->fs, &h->attrs[old_idx], name,
+                                        value, value_len, in_inode);
+               if (ret)
+                       return ret;
+               if (h->ibody_count <= old_idx) {
+                       /* Move entry from block to the end of ibody. */
+                       tmp = h->attrs[old_idx];
+                       memmove(h->attrs + h->ibody_count + 1,
+                               h->attrs + h->ibody_count,
+                               (old_idx - h->ibody_count) * sizeof(*h->attrs));
+                       h->attrs[h->ibody_count] = tmp;
+                       h->ibody_count++;
+               }
+               return 0;
+       }
+
+       if (h->ibody_count <= old_idx) {
+               block_free += EXT2_EXT_ATTR_LEN(name_len);
+               if (!h->attrs[old_idx].ea_ino)
+                       block_free +=
+                               EXT2_EXT_ATTR_SIZE(h->attrs[old_idx].value_len);
+       }
+
+       if (needed > block_free)
+               return EXT2_ET_EA_NO_SPACE;
+
+       if (old_idx >= 0) {
+               /* Update the existing entry. */
+               ret = xattr_update_entry(h->fs, &h->attrs[old_idx], name,
+                                        value, value_len, in_inode);
+               if (ret)
+                       return ret;
+               if (old_idx < h->ibody_count) {
+                       /*
+                        * Move entry from ibody to the block. Note that
+                        * entries in the block are sorted.
+                        */
+                       new_idx = xattr_find_position(h->attrs + h->ibody_count,
+                               h->count - h->ibody_count, name);
+                       new_idx += h->ibody_count - 1;
+                       tmp = h->attrs[old_idx];
+                       memmove(h->attrs + old_idx, h->attrs + old_idx + 1,
+                               (new_idx - old_idx) * sizeof(*h->attrs));
+                       h->attrs[new_idx] = tmp;
+                       h->ibody_count--;
+               }
+               return 0;
+       }
+
+       new_idx = xattr_find_position(h->attrs + h->ibody_count,
+                                     h->count - h->ibody_count, name);
+       new_idx += h->ibody_count;
+       add_to_ibody = 0;
+
+add_new:
+       if (h->count == h->capacity) {
+               ret = ext2fs_xattrs_expand(h, 4);
+               if (ret)
+                       return ret;
+       }
+
+       ret = xattr_update_entry(h->fs, &h->attrs[h->count], name, value,
+                                value_len, in_inode);
+       if (ret)
+               return ret;
+
+       tmp = h->attrs[h->count];
+       memmove(h->attrs + new_idx + 1, h->attrs + new_idx,
+               (h->count - new_idx)*sizeof(*h->attrs));
+       h->attrs[new_idx] = tmp;
+       if (add_to_ibody)
+               h->ibody_count++;
+       h->count++;
+       return 0;
+}
+
+int space_used(struct ext2_xattr *attrs, int count)
+{
+       int total = 0;
+       struct ext2_xattr *x;
+       char *shortname;
+       int i, len, name_idx;
+
+       for (i = 0, x = attrs; i < count; i++, x++) {
+               find_ea_index(x->name, &shortname, &name_idx);
+               len = strlen(shortname);
+               total += EXT2_EXT_ATTR_LEN(len);
+               if (!x->ea_ino)
+                       total += EXT2_EXT_ATTR_SIZE(x->value_len);
+       }
+       return total;
+}
+
+/*
+ * The minimum size of EA value when you start storing it in an external inode
+ * size of block - size of header - size of 1 entry - 4 null bytes
+ */
+#define EXT4_XATTR_MIN_LARGE_EA_SIZE(b)        \
+       ((b) - EXT2_EXT_ATTR_LEN(3) - sizeof(struct ext2_ext_attr_header) - 4)
+
+errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *h,
+                          const char *name,
                           const void *value,
                           size_t value_len)
 {
-       struct ext2_xattr *x, *last_empty;
+       ext2_filsys fs = h->fs;
+       const int inode_size = EXT2_INODE_SIZE(fs->super);
+       struct ext2_inode_large *inode = NULL;
+       struct ext2_xattr *x;
        char *new_value;
-       errcode_t err;
+       int ibody_free, block_free;
+       int in_inode = 0;
+       int old_idx = -1;
+       int extra_isize;
+       errcode_t ret;
 
-       EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
-       last_empty = NULL;
+       EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
 
-       err = ext2fs_get_mem(value_len, &new_value);
-       if (err)
-               return err;
-       if (!(handle->flags & XATTR_HANDLE_FLAG_RAW) &&
-           ((strcmp(key, "system.posix_acl_default") == 0) ||
-            (strcmp(key, "system.posix_acl_access") == 0))) {
-               err = convert_posix_acl_to_disk_buffer(value, value_len,
+       ret = ext2fs_get_mem(value_len, &new_value);
+       if (ret)
+               return ret;
+       if (!(h->flags & XATTR_HANDLE_FLAG_RAW) &&
+           ((strcmp(name, "system.posix_acl_default") == 0) ||
+            (strcmp(name, "system.posix_acl_access") == 0))) {
+               ret = convert_posix_acl_to_disk_buffer(value, value_len,
                                                       new_value, &value_len);
-               if (err)
-                       goto errout;
+               if (ret)
+                       goto out;
        } else
                memcpy(new_value, value, value_len);
 
-       for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
-               if (!x->name) {
-                       last_empty = x;
-                       continue;
+       /* Imitate kernel behavior by skipping update if value is the same. */
+       for (x = h->attrs; x < h->attrs + h->count; x++) {
+               if (!strcmp(x->name, name)) {
+                       if (!x->ea_ino && x->value_len == value_len &&
+                           !memcmp(x->value, new_value, value_len)) {
+                               ret = 0;
+                               goto out;
+                       }
+                       old_idx = x - h->attrs;
+                       break;
                }
+       }
 
-               /* Replace xattr */
-               if (strcmp(x->name, key) == 0) {
-                       ext2fs_free_mem(&x->value);
-                       x->value = new_value;
-                       x->value_len = value_len;
-                       handle->dirty = 1;
-                       return 0;
+       ret = ext2fs_get_memzero(inode_size, &inode);
+       if (ret)
+               goto out;
+       ret = ext2fs_read_inode_full(fs, h->ino,
+                                    (struct ext2_inode *)inode,
+                                    inode_size);
+       if (ret)
+               goto out;
+       if (inode_size > EXT2_GOOD_OLD_INODE_SIZE) {
+               extra_isize = inode->i_extra_isize;
+               if (extra_isize == 0) {
+                       extra_isize = fs->super->s_want_extra_isize;
+                       if (extra_isize == 0)
+                               extra_isize = sizeof(__u32);
                }
-       }
+               ibody_free = inode_size - EXT2_GOOD_OLD_INODE_SIZE;
+               ibody_free -= extra_isize;
+               /* Extended attribute magic and final null entry. */
+               ibody_free -= sizeof(__u32) * 2;
+               ibody_free -= space_used(h->attrs, h->ibody_count);
+       } else
+               ibody_free = 0;
 
-       /* Add attr to empty slot */
-       if (last_empty) {
-               err = ext2fs_get_mem(strlen(key) + 1, &last_empty->name);
-               if (err)
-                       goto errout;
-               strcpy(last_empty->name, key);
-               last_empty->value = new_value;
-               last_empty->value_len = value_len;
-               handle->dirty = 1;
-               handle->count++;
-               return 0;
+       /* Inline data can only go to ibody. */
+       if (strcmp(name, "system.data") == 0) {
+               if (h->ibody_count <= old_idx) {
+                       ret = EXT2_ET_FILESYSTEM_CORRUPTED;
+                       goto out;
+               }
+               ret = xattr_array_update(h, name, value, value_len, ibody_free,
+                                        0 /* block_free */, old_idx,
+                                        0 /* in_inode */);
+               if (ret)
+                       goto out;
+               goto write_out;
        }
 
-       /* Expand array, append slot */
-       err = ext2fs_xattrs_expand(handle, 4);
-       if (err)
-               goto errout;
-
-       x = handle->attrs + handle->length - 4;
-       err = ext2fs_get_mem(strlen(key) + 1, &x->name);
-       if (err)
-               goto errout;
-       strcpy(x->name, key);
+       block_free = fs->blocksize;
+       block_free -= sizeof(struct ext2_ext_attr_header);
+       /* Final null entry. */
+       block_free -= sizeof(__u32);
+       block_free -= space_used(h->attrs + h->ibody_count,
+                                h->count - h->ibody_count);
+
+       if (ext2fs_has_feature_ea_inode(fs->super) &&
+           value_len > EXT4_XATTR_MIN_LARGE_EA_SIZE(fs->blocksize))
+               in_inode = 1;
+
+       ret = xattr_array_update(h, name, value, value_len, ibody_free,
+                                block_free, old_idx, in_inode);
+       if (ret == EXT2_ET_EA_NO_SPACE && !in_inode &&
+           ext2fs_has_feature_ea_inode(fs->super))
+               ret = xattr_array_update(h, name, value, value_len, ibody_free,
+                                block_free, old_idx, 1 /* in_inode */);
+       if (ret)
+               goto out;
 
-       err = ext2fs_get_mem(value_len, &x->value);
-       if (err)
-               goto errout;
-       memcpy(x->value, value, value_len);
-       x->value_len = value_len;
-       handle->dirty = 1;
-       handle->count++;
-       return 0;
-errout:
+write_out:
+       ret = ext2fs_xattrs_write(h);
+out:
+       if (inode)
+               ext2fs_free_mem(&inode);
        ext2fs_free_mem(&new_value);
-       return err;
+       return ret;
 }
 
 errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
                              const char *key)
 {
        struct ext2_xattr *x;
+       struct ext2_xattr *end = handle->attrs + handle->count;
 
        EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
-       for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
-               if (!x->name)
-                       continue;
-
+       for (x = handle->attrs; x < end; x++) {
                if (strcmp(x->name, key) == 0) {
                        ext2fs_free_mem(&x->name);
                        ext2fs_free_mem(&x->value);
-                       x->value_len = 0;
-                       handle->dirty = 1;
+                       if (x->ea_ino)
+                               xattr_inode_dec_ref(handle->fs, x->ea_ino);
+                       memmove(x, x + 1, (end - x - 1)*sizeof(*x));
+                       memset(end - 1, 0, sizeof(*end));
+                       if (x < handle->attrs + handle->ibody_count)
+                               handle->ibody_count--;
                        handle->count--;
-                       return 0;
+                       return ext2fs_xattrs_write(handle);
                }
        }
 
@@ -1244,8 +1667,8 @@ errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
                return err;
 
        h->magic = EXT2_ET_MAGIC_EA_HANDLE;
-       h->length = 4;
-       err = ext2fs_get_arrayzero(h->length, sizeof(struct ext2_xattr),
+       h->capacity = 4;
+       err = ext2fs_get_arrayzero(h->capacity, sizeof(struct ext2_xattr),
                                   &h->attrs);
        if (err) {
                ext2fs_free_mem(&h);
@@ -1261,15 +1684,8 @@ errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
 errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle)
 {
        struct ext2_xattr_handle *h = *handle;
-       errcode_t err;
 
        EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
-       if (h->dirty) {
-               err = ext2fs_xattrs_write(h);
-               if (err)
-                       return err;
-       }
-
        xattrs_free_keys(h);
        ext2fs_free_mem(&h->attrs);
        ext2fs_free_mem(handle);
index 1b9c671a1cd0c8a72956d757a9ce02ea56c8dfae..bb7daf438f805c5de7be1d7dabca535687b0711d 100644 (file)
@@ -58,8 +58,10 @@ errcode_t ext2fs_sync_device(int fd, int flushb)
         * still is a race condition for those kernels, but this
         * reduces it greatly.)
         */
+#if defined(HAVE_FSYNC)
        if (fsync (fd) == -1)
                return errno;
+#endif
 
        if (flushb) {
                errcode_t       retval = 0;
index 6cd6fe6337565e1cd00a11db351fc1d88c02b1a7..d0061b82274e402d7cce0c2c9cb5862bdd0de87d 100644 (file)
@@ -564,7 +564,7 @@ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
 }
 
 int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap,
-                                  ino_t inode, int num)
+                                  ext2_ino_t inode, int num)
 {
        EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
        if ((inode < bitmap->start) || (inode+num-1 > bitmap->real_end)) {
index c0fc4ed1d6c7e14f7a257b789c90632434c15e49..0c1eef6c73d22ca260623d193fd7fc5fc4a47596 100644 (file)
@@ -42,11 +42,6 @@ static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data)
 
        retval = ext2fs_xattr_set(handle, "system.data",
                                  data->ea_data, data->ea_size);
-       if (retval)
-               goto err;
-
-       retval = ext2fs_xattrs_write(handle);
-
 err:
        (void) ext2fs_xattrs_close(&handle);
        return retval;
@@ -270,11 +265,6 @@ errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino)
                goto err;
 
        retval = ext2fs_xattr_remove(handle, "system.data");
-       if (retval)
-               goto err;
-
-       retval = ext2fs_xattrs_write(handle);
-
 err:
        (void) ext2fs_xattrs_close(&handle);
        return retval;
index 75a0596687d958e5f6aca0457e92f1b3aa0d4e72..91373674a7ca7962fc7c82cf9a421057b44948e6 100644 (file)
@@ -7,7 +7,11 @@
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
+#ifdef HAVE_WINSOCK_H
+#include <winsock.h>
+#else
 #include <arpa/inet.h>
+#endif
 
 #define printk printf
 #define KERN_ERR ""
index bff65c1bb106ddec43f134f5befe4852eb34c56a..1064ab53e6862b443271a0eb48db2e696b866a58 100644 (file)
@@ -50,7 +50,21 @@ static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
        if (link_count++ >= EXT2FS_MAX_NESTED_LINKS)
                return EXT2_ET_SYMLINK_LOOP;
 
-       if (ext2fs_inode_data_blocks(fs,&ei)) {
+       if (ext2fs_is_fast_symlink(&ei))
+               pathname = (char *)&(ei.i_block[0]);
+       else if (ei.i_flags & EXT4_INLINE_DATA_FL) {
+               retval = ext2fs_get_memzero(ei.i_size, &buffer);
+               if (retval)
+                       return retval;
+
+               retval = ext2fs_inline_data_get(fs, inode,
+                                               &ei, buffer, NULL);
+               if (retval) {
+                       ext2fs_free_mem(&buffer);
+                       return retval;
+               }
+               pathname = buffer;
+       } else {
                retval = ext2fs_bmap2(fs, inode, &ei, NULL, 0, 0, NULL, &blk);
                if (retval)
                        return retval;
@@ -65,8 +79,8 @@ static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
                        return retval;
                }
                pathname = buffer;
-       } else
-               pathname = (char *)&(ei.i_block[0]);
+       }
+
        retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
                            link_count, buf, res_inode);
        if (buffer)
diff --git a/lib/ext2fs/sparse_io.c b/lib/ext2fs/sparse_io.c
new file mode 100644 (file)
index 0000000..a307859
--- /dev/null
@@ -0,0 +1,541 @@
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#if !defined(ENABLE_LIBSPARSE)
+static errcode_t sparse_open(const char *name EXT2FS_ATTR((unused)),
+                            int flags EXT2FS_ATTR((unused)),
+                            io_channel *channel EXT2FS_ATTR((unused)))
+{
+       return EXT2_ET_UNIMPLEMENTED;
+}
+static errcode_t sparse_close(io_channel channel EXT2FS_ATTR((unused)))
+{
+       return EXT2_ET_UNIMPLEMENTED;
+}
+static struct struct_io_manager struct_sparse_manager = {
+       .magic                  = EXT2_ET_MAGIC_IO_MANAGER,
+       .name                   = "Android sparse I/O Manager",
+       .open                   = sparse_open,
+       .close                  = sparse_close,
+};
+static struct struct_io_manager struct_sparsefd_manager = {
+       .magic                  = EXT2_ET_MAGIC_IO_MANAGER,
+       .name                   = "Android sparse fd I/O Manager",
+       .open                   = sparse_open,
+       .close                  = sparse_close,
+};
+#else
+#include <sparse/sparse.h>
+
+struct sparse_map {
+       int                     fd;
+       char                    **blocks;
+       int                     block_size;
+       uint64_t                blocks_count;
+       char                    *file;
+       struct sparse_file      *sparse_file;
+       io_channel              channel;
+};
+
+struct sparse_io_params {
+       int                     fd;
+       char                    *file;
+       uint64_t                blocks_count;
+       unsigned int            block_size;
+};
+
+static errcode_t sparse_write_blk(io_channel channel, unsigned long block,
+                                 int count, const void *buf);
+
+static void free_sparse_blocks(struct sparse_map *sm)
+{
+       uint64_t i;
+
+       for (i = 0; i < sm->blocks_count; ++i)
+               free(sm->blocks[i]);
+       free(sm->blocks);
+       sm->blocks = NULL;
+}
+
+static int sparse_import_segment(void *priv, const void *data, int len,
+                                unsigned int block, unsigned int nr_blocks)
+{
+       struct sparse_map *sm = priv;
+
+       /* Ignore chunk headers, only write the data */
+       if (!nr_blocks || len % sm->block_size)
+               return 0;
+
+       return sparse_write_blk(sm->channel, block, nr_blocks, data);
+}
+
+static errcode_t io_manager_import_sparse(struct sparse_io_params *params,
+                                         struct sparse_map *sm, io_channel io)
+{
+       int fd;
+       errcode_t retval;
+       struct sparse_file *sparse_file;
+
+       if (params->fd < 0) {
+               fd = open(params->file, O_RDONLY);
+               if (fd < 0) {
+                       retval = -1;
+                       goto err_open;
+               }
+       } else
+               fd = params->fd;
+       sparse_file = sparse_file_import(fd, false, false);
+       if (!sparse_file) {
+               retval = -1;
+               goto err_sparse;
+       }
+
+       sm->block_size = sparse_file_block_size(sparse_file);
+       sm->blocks_count = (sparse_file_len(sparse_file, 0, 0) - 1)
+                               / sm->block_size + 1;
+       sm->blocks = calloc(sm->blocks_count, sizeof(char*));
+       if (!sm->blocks) {
+               retval = -1;
+               goto err_alloc;
+       }
+       io->block_size = sm->block_size;
+
+       retval = sparse_file_foreach_chunk(sparse_file, true, false,
+                                          sparse_import_segment, sm);
+
+       if (retval)
+               free_sparse_blocks(sm);
+err_alloc:
+       sparse_file_destroy(sparse_file);
+err_sparse:
+       close(fd);
+err_open:
+       return retval;
+}
+
+static errcode_t io_manager_configure(struct sparse_io_params *params,
+                                     int flags, io_channel io)
+{
+       errcode_t retval;
+       uint64_t img_size;
+       struct sparse_map *sm = calloc(1, sizeof(*sm));
+       if (!sm)
+               return EXT2_ET_NO_MEMORY;
+
+       sm->file = params->file;
+       sm->channel = io;
+       io->private_data = sm;
+       retval = io_manager_import_sparse(params, sm, io);
+       if (retval) {
+               if (!params->block_size || !params->blocks_count) {
+                       retval = -EINVAL;
+                       goto err_params;
+               }
+               sm->block_size = params->block_size;
+               sm->blocks_count = params->blocks_count;
+               sm->blocks = calloc(params->blocks_count, sizeof(void*));
+               if (!sm->blocks) {
+                       retval = EXT2_ET_NO_MEMORY;
+                       goto err_alloc;
+               }
+       }
+       io->block_size = sm->block_size;
+       img_size = (uint64_t)sm->block_size * sm->blocks_count;
+
+       if (flags & IO_FLAG_RW) {
+               sm->sparse_file = sparse_file_new(sm->block_size, img_size);
+               if (!sm->sparse_file) {
+                       retval = EXT2_ET_NO_MEMORY;
+                       goto err_alloc;
+               }
+               if (params->fd < 0) {
+                       sm->fd = open(params->file, O_CREAT | O_RDWR | O_TRUNC,
+                                     0644);
+                       if (sm->fd < 0) {
+                               retval = errno;
+                               goto err_open;
+                       }
+               } else
+                       sm->fd = params->fd;
+       } else {
+               sm->fd = -1;
+               sm->sparse_file = NULL;
+       }
+       return 0;
+
+err_open:
+       sparse_file_destroy(sm->sparse_file);
+err_alloc:
+       free_sparse_blocks(sm);
+err_params:
+       free(sm);
+       return retval;
+}
+
+static errcode_t sparse_open_channel(struct sparse_io_params *sparse_params,
+                                    int flags, io_channel *channel)
+{
+       io_channel io;
+
+       io = calloc(1, sizeof(struct struct_io_channel));
+       io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+       io->block_size = 0;
+       io->refcount = 1;
+       *channel = io;
+       return io_manager_configure(sparse_params, flags, io);
+}
+
+static errcode_t read_sparse_argv(const char *name, bool is_fd,
+                                 struct sparse_io_params *sparse_params)
+{
+       int ret;
+       sparse_params->fd = -1;
+       sparse_params->block_size = 0;
+       sparse_params->blocks_count = 0;
+
+       sparse_params->file = malloc(strlen(name) + 1);
+       if (!sparse_params->file) {
+               fprintf(stderr, "failed to alloc %zu\n", strlen(name) + 1);
+               return EXT2_ET_NO_MEMORY;
+       }
+
+       if (is_fd) {
+               ret = sscanf(name, "%d:%llu:%u", &sparse_params->fd,
+                            (unsigned long long *)&sparse_params->blocks_count,
+                            &sparse_params->block_size);
+       } else {
+               ret = sscanf(name, "%[^:]%*[:]%llu%*[:]%u", sparse_params->file,
+                            (unsigned long long *)&sparse_params->blocks_count,
+                            &sparse_params->block_size);
+       }
+
+       if (ret < 1) {
+               free(sparse_params->file);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static errcode_t sparse_open(const char *name, int flags, io_channel *channel)
+{
+       errcode_t retval;
+       struct sparse_io_params sparse_params;
+
+       retval = read_sparse_argv(name, false, &sparse_params);
+       if (retval)
+               return EXT2_ET_BAD_DEVICE_NAME;
+
+       retval = sparse_open_channel(&sparse_params, flags, channel);
+       if (retval)
+               return retval;
+       (*channel)->manager = sparse_io_manager;
+
+       return retval;
+}
+
+static errcode_t sparsefd_open(const char *name, int flags, io_channel *channel)
+{
+       errcode_t retval;
+       struct sparse_io_params sparse_params;
+
+       retval = read_sparse_argv(name, true, &sparse_params);
+       if (retval)
+               return EXT2_ET_BAD_DEVICE_NAME;
+
+       retval = sparse_open_channel(&sparse_params, flags, channel);
+       if (retval)
+               return retval;
+       (*channel)->manager = sparsefd_io_manager;
+
+       return retval;
+}
+
+static errcode_t sparse_merge_blocks(struct sparse_map *sm, uint64_t start,
+                                       uint64_t num)
+{
+       char *buf;
+       uint64_t i;
+       unsigned int block_size = sm->block_size;
+       errcode_t retval = 0;
+
+       buf = calloc(num, block_size);
+       if (!buf) {
+               fprintf(stderr, "failed to alloc %lu\n", num * block_size);
+               return EXT2_ET_NO_MEMORY;
+       }
+
+       for (i = 0; i < num; i++) {
+               memcpy(buf + i * block_size, sm->blocks[start + i] , block_size);
+               free(sm->blocks[start + i]);
+               sm->blocks[start + i] = NULL;
+       }
+
+       /* free_sparse_blocks will release this buf. */
+       sm->blocks[start] = buf;
+
+       retval = sparse_file_add_data(sm->sparse_file, sm->blocks[start],
+                                       block_size * num, start);
+
+       return retval;
+}
+
+static errcode_t sparse_close_channel(io_channel channel)
+{
+       uint64_t i;
+       errcode_t retval = 0;
+       struct sparse_map *sm = channel->private_data;
+
+       if (sm->sparse_file) {
+               int64_t chunk_start = (sm->blocks[0] == NULL) ? -1 : 0;
+               for (i = 0; i < sm->blocks_count; ++i) {
+                       if (!sm->blocks[i] && chunk_start != -1) {
+                               retval = sparse_merge_blocks(sm, chunk_start, i - chunk_start);
+                               chunk_start = -1;
+                       } else if (sm->blocks[i] && chunk_start == -1) {
+                               chunk_start = i;
+                       }
+                       if (retval)
+                               goto ret;
+               }
+               if (chunk_start != -1) {
+                       retval = sparse_merge_blocks(sm, chunk_start,
+                                                       sm->blocks_count - chunk_start);
+                       if (retval)
+                               goto ret;
+               }
+               retval = sparse_file_write(sm->sparse_file, sm->fd,
+                                          /*gzip*/0, /*sparse*/1, /*crc*/0);
+       }
+
+ret:
+       if (sm->sparse_file)
+               sparse_file_destroy(sm->sparse_file);
+       free_sparse_blocks(sm);
+       free(sm->file);
+       free(sm);
+       free(channel);
+       return retval;
+}
+
+static errcode_t sparse_close(io_channel channel)
+{
+       errcode_t retval;
+       struct sparse_map *sm = channel->private_data;
+       int fd = sm->fd;
+
+       retval = sparse_close_channel(channel);
+       if (fd >= 0)
+               close(fd);
+
+       return retval;
+}
+
+static errcode_t sparse_set_blksize(io_channel channel, int blksize)
+{
+       channel->block_size = blksize;
+       return 0;
+}
+
+static blk64_t block_to_sparse_block(blk64_t block, blk64_t *offset,
+                              io_channel channel, struct sparse_map *sm)
+{
+       int ratio;
+       blk64_t ret = block;
+
+       ratio = sm->block_size / channel->block_size;
+       ret /= ratio;
+       *offset = (block % ratio) * channel->block_size;
+
+       return ret;
+}
+
+static errcode_t check_block_size(io_channel channel, struct sparse_map *sm)
+{
+       if (sm->block_size >= channel->block_size)
+               return 0;
+       return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+}
+
+static errcode_t sparse_read_blk64(io_channel channel, blk64_t block,
+                                  int count, void *buf)
+{
+       int i;
+       char *out = buf;
+       blk64_t offset = 0, cur_block;
+       struct sparse_map *sm = channel->private_data;
+
+       if (check_block_size(channel, sm))
+               return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+
+       if (count < 0) { //partial read
+               count = -count;
+               cur_block = block_to_sparse_block(block, &offset, channel, sm);
+               if (sm->blocks[cur_block])
+                       memcpy(out, (sm->blocks[cur_block]) + offset, count);
+               else
+                       memset(out, 0, count);
+       } else {
+               for (i = 0; i < count; ++i) {
+                       cur_block = block_to_sparse_block(block + i, &offset,
+                                                   channel, sm);
+                       if (sm->blocks[cur_block])
+                               memcpy(out + (i * channel->block_size),
+                                      sm->blocks[cur_block] + offset,
+                                      channel->block_size);
+                       else if (sm->blocks)
+                               memset(out + (i * channel->block_size), 0,
+                                      channel->block_size);
+               }
+       }
+       return 0;
+}
+
+static errcode_t sparse_read_blk(io_channel channel, unsigned long block,
+                                int count, void *buf)
+{
+       return sparse_read_blk64(channel, block, count, buf);
+}
+
+static errcode_t sparse_write_blk64(io_channel channel, blk64_t block,
+                                   int count, const void *buf)
+{
+       int i;
+       blk64_t offset = 0, cur_block;
+       const char *in = buf;
+       struct sparse_map *sm = channel->private_data;
+
+       if (check_block_size(channel, sm))
+               return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+
+       if (count < 0) { //partial write
+               count = -count;
+               cur_block = block_to_sparse_block(block, &offset, channel,
+                                                 sm);
+               if (!sm->blocks[cur_block]) {
+                       sm->blocks[cur_block] = calloc(1, sm->block_size);
+                       if (!sm->blocks[cur_block])
+                               return EXT2_ET_NO_MEMORY;
+               }
+               memcpy(sm->blocks[cur_block] + offset, in, count);
+       } else {
+               for (i = 0; i < count; ++i) {
+                       if (block + i >= sm->blocks_count)
+                               return 0;
+                       cur_block = block_to_sparse_block(block + i, &offset,
+                                                   channel, sm);
+                       if (!sm->blocks[cur_block]) {
+                               sm->blocks[cur_block] =
+                                       calloc(1, sm->block_size);
+                               if (!sm->blocks[cur_block])
+                                       return EXT2_ET_NO_MEMORY;
+                       }
+                       memcpy(sm->blocks[cur_block] + offset,
+                              in + (i * channel->block_size),
+                              channel->block_size);
+               }
+       }
+       return 0;
+}
+
+static errcode_t sparse_write_blk(io_channel channel, unsigned long block,
+                                 int count, const void *buf)
+{
+       return sparse_write_blk64(channel, block, count, buf);
+}
+
+static errcode_t sparse_discard(io_channel channel __attribute__((unused)),
+                               blk64_t blk, unsigned long long count)
+{
+       blk64_t cur_block, offset;
+       struct sparse_map *sm = channel->private_data;
+
+       if (check_block_size(channel, sm))
+               return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+
+       for (unsigned long long i = 0; i < count; ++i) {
+               if (blk + i >= sm->blocks_count)
+                       return 0;
+               cur_block = block_to_sparse_block(blk + i, &offset, channel,
+                                                 sm);
+               if (!sm->blocks[cur_block])
+                       continue;
+               free(sm->blocks[cur_block]);
+               sm->blocks[cur_block] = NULL;
+       }
+       return 0;
+}
+
+static errcode_t sparse_zeroout(io_channel channel, blk64_t blk,
+                               unsigned long long count)
+{
+       return sparse_discard(channel, blk, count);
+}
+
+static errcode_t sparse_flush(io_channel channel __attribute__((unused)))
+{
+       return 0;
+}
+
+static errcode_t sparse_set_option(io_channel channel __attribute__((unused)),
+                                   const char *option __attribute__((unused)),
+                                   const char *arg __attribute__((unused)))
+{
+       return 0;
+}
+
+static errcode_t sparse_cache_readahead(
+                       io_channel channel __attribute__((unused)),
+                       blk64_t blk __attribute__((unused)),
+                       unsigned long long count __attribute__((unused)))
+{
+       return 0;
+}
+
+static struct struct_io_manager struct_sparse_manager = {
+       .magic                  = EXT2_ET_MAGIC_IO_MANAGER,
+       .name                   = "Android sparse I/O Manager",
+       .open                   = sparse_open,
+       .close                  = sparse_close,
+       .set_blksize            = sparse_set_blksize,
+       .read_blk               = sparse_read_blk,
+       .write_blk              = sparse_write_blk,
+       .flush                  = sparse_flush,
+       .write_byte             = NULL,
+       .set_option             = sparse_set_option,
+       .get_stats              = NULL,
+       .read_blk64             = sparse_read_blk64,
+       .write_blk64            = sparse_write_blk64,
+       .discard                = sparse_discard,
+       .cache_readahead        = sparse_cache_readahead,
+       .zeroout                = sparse_zeroout,
+};
+
+static struct struct_io_manager struct_sparsefd_manager = {
+       .magic                  = EXT2_ET_MAGIC_IO_MANAGER,
+       .name                   = "Android sparse fd I/O Manager",
+       .open                   = sparsefd_open,
+       .close                  = sparse_close,
+       .set_blksize            = sparse_set_blksize,
+       .read_blk               = sparse_read_blk,
+       .write_blk              = sparse_write_blk,
+       .flush                  = sparse_flush,
+       .write_byte             = NULL,
+       .set_option             = sparse_set_option,
+       .get_stats              = NULL,
+       .read_blk64             = sparse_read_blk64,
+       .write_blk64            = sparse_write_blk64,
+       .discard                = sparse_discard,
+       .cache_readahead        = sparse_cache_readahead,
+       .zeroout                = sparse_zeroout,
+};
+
+#endif
+
+io_manager sparse_io_manager = &struct_sparse_manager;
+io_manager sparsefd_io_manager = &struct_sparsefd_manager;
index d63fc55fd49612381ad5bf8030f0f7daa68ee7cc..b9d8f55796605ef1c793c072c13019331cfe40df 100644 (file)
@@ -170,7 +170,7 @@ void ext2fs_swap_ext_attr_entry(struct ext2_ext_attr_entry *to_entry,
                                struct ext2_ext_attr_entry *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_inum  = ext2fs_swab32(from_entry->e_value_inum);
        to_entry->e_value_size  = ext2fs_swab32(from_entry->e_value_size);
        to_entry->e_hash        = ext2fs_swab32(from_entry->e_hash);
 }
@@ -210,18 +210,24 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
                            struct ext2_inode_large *f, int hostorder,
                            int bufsize)
 {
-       unsigned i, has_data_blocks, extra_isize, attr_magic;
-       int has_extents = 0;
-       int has_inline_data = 0;
-       int islnk = 0;
+       unsigned i, extra_isize, attr_magic;
+       int has_extents, has_inline_data, islnk, fast_symlink;
        int inode_size;
        __u32 *eaf, *eat;
 
-       if (hostorder && LINUX_S_ISLNK(f->i_mode))
-               islnk = 1;
+       /*
+        * Note that t and f may point to the same address. That's why
+        * if (hostorder) condition is executed before swab calls and
+        * if (!hostorder) afterwards.
+        */
+       if (hostorder) {
+               islnk = LINUX_S_ISLNK(f->i_mode);
+               fast_symlink = ext2fs_is_fast_symlink(EXT2_INODE(f));
+               has_extents = (f->i_flags & EXT4_EXTENTS_FL) != 0;
+               has_inline_data = (f->i_flags & EXT4_INLINE_DATA_FL) != 0;
+       }
+
        t->i_mode = ext2fs_swab16(f->i_mode);
-       if (!hostorder && LINUX_S_ISLNK(t->i_mode))
-               islnk = 1;
        t->i_uid = ext2fs_swab16(f->i_uid);
        t->i_size = ext2fs_swab32(f->i_size);
        t->i_atime = ext2fs_swab32(f->i_atime);
@@ -231,27 +237,21 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
        t->i_gid = ext2fs_swab16(f->i_gid);
        t->i_links_count = ext2fs_swab16(f->i_links_count);
        t->i_file_acl = ext2fs_swab32(f->i_file_acl);
-       if (hostorder)
-               has_data_blocks = ext2fs_inode_data_blocks(fs,
-                                          (struct ext2_inode *) f);
        t->i_blocks = ext2fs_swab32(f->i_blocks);
-       if (!hostorder)
-               has_data_blocks = ext2fs_inode_data_blocks(fs,
-                                          (struct ext2_inode *) t);
-       if (hostorder && (f->i_flags & EXT4_EXTENTS_FL))
-               has_extents = 1;
-       if (hostorder && (f->i_flags & EXT4_INLINE_DATA_FL))
-               has_inline_data = 1;
        t->i_flags = ext2fs_swab32(f->i_flags);
-       if (!hostorder && (t->i_flags & EXT4_EXTENTS_FL))
-               has_extents = 1;
-       if (!hostorder && (t->i_flags & EXT4_INLINE_DATA_FL))
-               has_inline_data = 1;
-       t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
+       t->i_size_high = ext2fs_swab32(f->i_size_high);
+
+       if (!hostorder) {
+               islnk = LINUX_S_ISLNK(t->i_mode);
+               fast_symlink = ext2fs_is_fast_symlink(EXT2_INODE(t));
+               has_extents = (t->i_flags & EXT4_EXTENTS_FL) != 0;
+               has_inline_data = (t->i_flags & EXT4_INLINE_DATA_FL) != 0;
+       }
+
        /*
         * Extent data and inline data are swapped on access, not here
         */
-       if (!has_extents && !has_inline_data && (!islnk || has_data_blocks)) {
+       if (!has_extents && !has_inline_data && (!islnk || !fast_symlink)) {
                for (i = 0; i < EXT2_N_BLOCKS; i++)
                        t->i_block[i] = ext2fs_swab32(f->i_block[i]);
        } else if (t != f) {
index 0e6f9a9fd14e1cc554facd5ffdf34b38fed998d5..607396def0f8d60fb37286b12285729134e9cb17 100644 (file)
@@ -174,3 +174,14 @@ cleanup:
                ext2fs_free_mem(&block_buf);
        return retval;
 }
+
+/*
+ * Test whether an inode is a fast symlink.
+ *
+ * A fast symlink has its symlink data stored in inode->i_block.
+ */
+int ext2fs_is_fast_symlink(struct ext2_inode *inode)
+{
+       return LINUX_S_ISLNK(inode->i_mode) && EXT2_I_SIZE(inode) &&
+              EXT2_I_SIZE(inode) < sizeof(inode->i_block);
+}
index f7c50d1be5a88e6e6d68bb0bae12e7f689439e50..ee828be7a2d53caecd0454cf9e5b4e46fff6d09a 100644 (file)
@@ -146,8 +146,10 @@ static void test_abort(io_channel channel, unsigned long block)
 
 static char *safe_getenv(const char *arg)
 {
+#if !defined(_WIN32)
        if ((getuid() != geteuid()) || (getgid() != getegid()))
                return NULL;
+#endif
 #if HAVE_PRCTL
        if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
                return NULL;
index 64141954e6a57ea88d73488054199d774a8a5bc8..98a6756f4ae3034430649710d7c673f919a560dd 100644 (file)
@@ -721,6 +721,7 @@ static errcode_t unixfd_open(const char *str_fd, int flags,
        int fd_flags;
 
        fd = atoi(str_fd);
+#if defined(HAVE_FCNTL)
        fd_flags = fcntl(fd, F_GETFD);
        if (fd_flags == -1)
                return -EBADF;
@@ -734,6 +735,7 @@ static errcode_t unixfd_open(const char *str_fd, int flags,
        if (fd_flags & O_DIRECT)
                flags |= IO_FLAG_DIRECT_IO;
 #endif
+#endif  /* HAVE_FCNTL */
 
        return unix_open_channel(str_fd, fd, flags, channel, unixfd_io_manager);
 }
@@ -1033,8 +1035,10 @@ static errcode_t unix_flush(io_channel channel)
 #ifndef NO_IO_CACHE
        retval = flush_cached_blocks(channel, data, 0);
 #endif
+#ifdef HAVE_FSYNC
        if (!retval && fsync(data->dev) != 0)
                return errno;
+#endif
        return retval;
 }
 
diff --git a/lib/ss/Android.bp b/lib/ss/Android.bp
new file mode 100644 (file)
index 0000000..06925d7
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_ss",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "ss_err.c",
+        "std_rqs.c",
+        "invocation.c",
+        "help.c",
+        "execute_cmd.c",
+        "listen.c",
+        "parse.c",
+        "error.c",
+        "prompt.c",
+        "request_tbl.c",
+        "list_rqs.c",
+        "pager.c",
+        "requests.c",
+        "data.c",
+        "get_readline.c",
+    ],
+    shared_libs: ["libext2_com_err"],
+    cflags: [
+        "-W",
+        "-Wall",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/ss/Android.mk b/lib/ss/Android.mk
deleted file mode 100644 (file)
index c19accc..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_ss_src_files := \
-       ss_err.c \
-       std_rqs.c \
-       invocation.c help.c \
-       execute_cmd.c \
-       listen.c \
-       parse.c \
-       error.c \
-       prompt.c \
-       request_tbl.c \
-       list_rqs.c \
-       pager.c \
-       requests.c \
-       data.c \
-       get_readline.c
-
-libext2_ss_c_includes := external/e2fsprogs/lib
-
-libext2_ss_cflags := -O2 -g -W -Wall
-
-libext2_ss_shared_libraries := \
-       libext2_com_err
-
-libext2_ss_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_ss_src_files)
-LOCAL_C_INCLUDES := $(libext2_ss_c_includes)
-LOCAL_CFLAGS := $(libext2_ss_cflags)
-LOCAL_SHARED_LIBRARIES := $(libext2_ss_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_ss_system_shared_libraries)
-LOCAL_MODULE := libext2_ss
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_ss_src_files)
-LOCAL_C_INCLUDES := $(libext2_ss_c_includes)
-LOCAL_CFLAGS := $(libext2_ss_cflags)
-LOCAL_STATIC_LIBRARIES := libc
-LOCAL_MODULE := libext2_ss
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_ss_src_files)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2_ss_shared_libraries))
-LOCAL_C_INCLUDES := $(libext2_ss_c_includes)
-LOCAL_CFLAGS := $(libext2_ss_cflags)
-LOCAL_MODULE := libext2_ss-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
index f4953f070ba3d93babd717fc37df1bbd442453e8..ee18dc889335d9ee7dde3b4dd26835dd8e720da4 100644 (file)
@@ -163,7 +163,7 @@ test_ss: test_ss.o test_cmd.o $(DEPLIBSS) $(DEPLIBCOM_ERR)
        $(Q) $(CC) -o $@ test_ss.o test_cmd.o $(ALL_CFLAGS) $(ALL_LDFLAGS) \
                $(LIBSS) $(LIBCOM_ERR) $(SYSLIBS)
 
-check:: all test_ss
+fullcheck check:: all test_ss
        $(E) "  RUN TEST test_ss"
        -@($(TESTENV) ./test_ss -f $(srcdir)/test_script > test_out 2>&1; exit 0)
        $(Q) if diff test_out $(srcdir)/test_script_expected > test.diff; then \
diff --git a/lib/support/Android.bp b/lib/support/Android.bp
new file mode 100644 (file)
index 0000000..24414a4
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_quota",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "dict.c",
+        "mkquota.c",
+        "parse_qtype.c",
+        "plausible.c",
+        "profile.c",
+        "profile_helpers.c",
+        "prof_err.c",
+        "quotaio.c",
+        "quotaio_tree.c",
+        "quotaio_v2.c",
+    ],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libext2_blkid",
+    ],
+
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-macro-redefined",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
+
+cc_library_shared {
+    name: "libext2_profile",
+    host_supported: true,
+    unique_host_soname: true,
+
+    srcs: [
+        "prof_err.c",
+        "profile.c",
+    ],
+    cflags = [
+        "-W",
+        "-Wall",
+    ],
+    shared_libs: ["libext2_com_err"],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/support/Android.mk b/lib/support/Android.mk
deleted file mode 100644 (file)
index fefd058..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_quota_src_files := \
-       dict.c \
-       mkquota.c \
-       parse_qtype.c \
-       plausible.c \
-       profile.c \
-       profile_helpers.c \
-       prof_err.c \
-       quotaio.c \
-       quotaio_tree.c \
-       quotaio_v2.c
-
-libext2_quota_c_includes := external/e2fsprogs/lib
-
-libext2_quota_cflags := -O2 -g -W -Wall
-
-libext2_quota_shared_libraries := libext2fs libext2_com_err libext2_blkid
-
-libext2_quota_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_quota_src_files)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_quota_system_shared_libraries)
-LOCAL_C_INCLUDES := $(libext2_quota_c_includes)
-LOCAL_CFLAGS := $(libext2_quota_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := libc $(libext2_quota_shared_libraries)
-LOCAL_MODULE := libext2_quota
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-libext2_quota_static_libraries := libext2fs libext2_com_err
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_quota_src_files)
-LOCAL_C_INCLUDES := $(libext2_quota_c_includes)
-LOCAL_CFLAGS := $(libext2_quota_cflags)
-LOCAL_STATIC_LIBRARIES := libc $(libext2_quota_static_libraries)
-LOCAL_MODULE := libext2_quota
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_quota_src_files)
-LOCAL_C_INCLUDES := $(libext2_quota_c_includes)
-LOCAL_CFLAGS := $(libext2_quota_cflags)
-LOCAL_MODULE := libext2_quota-host
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2_quota_shared_libraries))
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-libext2_profile_src_files :=  \
-       prof_err.c \
-       profile.c
-
-libext2_profile_shared_libraries := \
-       libext2_com_err
-
-libext2_profile_system_shared_libraries := libc
-
-libext2_profile_c_includes := external/e2fsprogs/lib
-
-libext2_profile_cflags := -O2 -g -W -Wall
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_profile_src_files)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_profile_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(libext2_profile_shared_libraries)
-LOCAL_C_INCLUDES := $(libext2_profile_c_includes)
-LOCAL_CFLAGS := $(libext2_profile_cflags)
-LOCAL_MODULE := libext2_profile
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_profile_src_files)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2_profile_shared_libraries))
-LOCAL_C_INCLUDES := $(libext2_profile_c_includes)
-LOCAL_CFLAGS := $(libext2_profile_cflags)
-LOCAL_MODULE := libext2_profile-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
index d5a6f26deb74a48b3cec4d2119da642e2b9eebc2..40206b748b7c7816e38cb1a93afbc9847b3e8c09 100644 (file)
@@ -79,7 +79,7 @@ clean::
                ../libsupport.a ../libsupport_p.a $(SMANPAGES) \
                prof_err.c prof_err.h test_profile test_cstring
 
-#check:: tst_uuid
+#fullcheck check:: tst_uuid
 #      LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid
 
 mostlyclean:: clean
diff --git a/lib/uuid/Android.bp b/lib/uuid/Android.bp
new file mode 100644 (file)
index 0000000..d173788
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_uuid",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "clear.c",
+        "compare.c",
+        "copy.c",
+        "gen_uuid.c",
+        "isnull.c",
+        "pack.c",
+        "parse.c",
+        "unpack.c",
+        "unparse.c",
+        "uuid_time.c",
+    ],
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-unused-function",
+        "-Wno-unused-parameter",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/uuid/Android.mk b/lib/uuid/Android.mk
deleted file mode 100644 (file)
index 91d6836..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_uuid_src_files := \
-       clear.c \
-       compare.c \
-       copy.c \
-       gen_uuid.c \
-       isnull.c \
-       pack.c \
-       parse.c \
-       unpack.c \
-       unparse.c \
-       uuid_time.c
-
-
-libext2_uuid_c_includes := external/e2fsprogs/lib
-
-libext2_uuid_cflags := -O2 -g -W -Wall \
-       -Wno-unused-function \
-       -Wno-unused-parameter
-
-libext2_uuid_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_uuid_src_files)
-LOCAL_C_INCLUDES := $(libext2_uuid_c_includes)
-LOCAL_CFLAGS := $(libext2_uuid_cflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) $(LOCAL_PATH)/..
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_uuid_system_shared_libraries)
-LOCAL_MODULE := libext2_uuid
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_uuid_src_files)
-LOCAL_C_INCLUDES := $(libext2_uuid_c_includes)
-LOCAL_CFLAGS := $(libext2_uuid_cflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_MODULE := libext2_uuid-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_uuid_src_files)
-LOCAL_C_INCLUDES := $(libext2_uuid_c_includes)
-LOCAL_CFLAGS := $(libext2_uuid_cflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_STATIC_LIBRARIES := libc
-LOCAL_MODULE := libext2_uuid_static
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_uuid_src_files)
-LOCAL_C_INCLUDES := $(libext2_uuid_c_includes)
-LOCAL_CFLAGS := $(libext2_uuid_cflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_MODULE := libext2_uuid-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_STATIC_LIBRARY)
index a29814496f9a5cfea96387fc0bbe4fd5aff8ab27..4b44418299d739f7f087bdf7ee2b08e2da495939 100644 (file)
@@ -171,7 +171,7 @@ clean::
                ../libuuid.a ../libuuid_p.a tst_uuid uuid_time \
                uuid.pc uuid_types.h $(SMANPAGES)
 
-check:: tst_uuid
+fullcheck check:: tst_uuid
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid
 
 mostlyclean:: clean
diff --git a/misc/Android.bp b/misc/Android.bp
new file mode 100644 (file)
index 0000000..ae7d9b6
--- /dev/null
@@ -0,0 +1,221 @@
+// Copyright 2017 The Android Open Source Project
+
+// Library used to export files from this directory to other programs in this
+// project.
+cc_library {
+    name: "libext2_misc",
+    host_supported: true,
+
+    srcs: [
+        "create_inode.c",
+    ],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2_quota",
+        "libext2fs",
+    ],
+    system_shared_libs: ["libc"],
+    export_include_dirs: ["."],
+}
+
+//########################################################################
+// Build mke2fs
+
+cc_binary {
+    name: "mke2fs",
+    host_supported: true,
+
+    srcs: [
+        "mke2fs.c",
+        "util.c",
+        "mk_hugefiles.c",
+        "default_profile.c",
+    ],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_blkid",
+        "libext2_misc",
+        "libext2_uuid",
+        "libext2_quota",
+        "libext2_com_err",
+        "libext2_e2p",
+    ],
+    system_shared_libs: ["libc"],
+    include_dirs: ["external/e2fsprogs/e2fsck"],
+}
+
+//##########################################################################
+// Build tune2fs
+
+cc_defaults {
+    name: "tune2fs-defaults",
+    srcs: [
+        "tune2fs.c",
+        "util.c",
+    ],
+    cflags: [
+        "-W",
+        "-Wall",
+        "-DNO_RECOVERY",
+        "-Wno-macro-redefined",
+    ],
+    include_dirs: ["external/e2fsprogs/e2fsck"],
+}
+
+tune2fs_libs = [
+    "libext2_com_err",
+    "libext2_blkid",
+    "libext2_quota",
+    "libext2_uuid",
+    "libext2_e2p",
+    "libext2fs",
+]
+
+cc_binary {
+    name: "tune2fs",
+    host_supported: true,
+    defaults: ["tune2fs-defaults"],
+
+    shared_libs: tune2fs_libs,
+    system_shared_libs: ["libc"],
+}
+
+cc_binary {
+    name: "tune2fs_static",
+    static_executable: true,
+    defaults: ["tune2fs-defaults"],
+
+    static_libs: tune2fs_libs + ["libc"],
+}
+
+cc_library_static {
+    name: "libtune2fs",
+    defaults: ["tune2fs-defaults"],
+
+    cflags: ["-DBUILD_AS_LIB"],
+    static_libs: tune2fs_libs,
+}
+
+//########################################################################
+// Build badblocks
+
+cc_binary {
+    name: "badblocks",
+    host_supported: true,
+
+    srcs: ["badblocks.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libext2_uuid",
+        "libext2_blkid",
+        "libext2_e2p",
+    ],
+    system_shared_libs: ["libc"],
+}
+
+//########################################################################
+// Build chattr
+
+cc_binary {
+    name: "chattr",
+    host_supported: true,
+
+    srcs: ["chattr.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2_com_err",
+        "libext2_e2p",
+    ],
+    system_shared_libs: ["libc"],
+}
+
+//########################################################################
+// Build lsattr
+
+cc_defaults {
+    name: "lsattr-defaults",
+    srcs: ["lsattr.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+}
+
+lsattr_libs = [
+    "libext2_com_err",
+    "libext2_e2p",
+]
+
+cc_binary {
+    name: "lsattr",
+    host_supported: true,
+    defaults: ["lsattr-defaults"],
+
+    shared_libs: lsattr_libs,
+    system_shared_libs: ["libc"],
+}
+
+cc_binary {
+    name: "lsattr_static",
+    static_executable: true,
+    defaults: ["lsattr-defaults"],
+
+    static_libs: lsattr_libs + ["libc"],
+}
+
+//########################################################################
+// Build blkid
+
+cc_binary {
+    name: "blkid",
+
+    srcs: ["blkid.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_blkid",
+        "libext2_com_err",
+        "libext2_e2p",
+    ],
+    system_shared_libs: ["libc"],
+}
+
+//########################################################################
+// Build e4crypt
+
+cc_binary {
+    name: "e4crypt",
+    host_supported: true,
+
+    srcs: ["e4crypt.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_uuid",
+    ],
+    system_shared_libs: ["libc"],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+//##########################################################################
+// Build e2image
+
+cc_binary {
+    name: "e2image",
+    host_supported: true,
+
+    srcs: ["e2image.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_blkid",
+        "libext2_com_err",
+        "libext2_quota",
+    ],
+    system_shared_libs: ["libc"],
+}
diff --git a/misc/Android.mk b/misc/Android.mk
deleted file mode 100644 (file)
index d960737..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-#########################################################################
-# Build mke2fs
-mke2fs_src_files := \
-       mke2fs.c \
-       util.c \
-       mk_hugefiles.c \
-       default_profile.c \
-       create_inode.c
-
-mke2fs_c_includes := \
-       external/e2fsprogs/e2fsck
-
-mke2fs_cflags := -O2 -g -W -Wall
-
-mke2fs_shared_libraries := \
-       libext2fs \
-       libext2_blkid \
-       libext2_uuid \
-       libext2_quota \
-       libext2_com_err \
-       libext2_e2p
-
-mke2fs_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(mke2fs_src_files)
-LOCAL_C_INCLUDES := $(mke2fs_c_includes)
-LOCAL_CFLAGS := $(mke2fs_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(mke2fs_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(mke2fs_shared_libraries)
-LOCAL_MODULE := mke2fs
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(mke2fs_src_files)
-LOCAL_C_INCLUDES := $(mke2fs_c_includes)
-LOCAL_CFLAGS := $(mke2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(mke2fs_shared_libraries))
-LOCAL_MODULE := mke2fs_host
-LOCAL_MODULE_STEM := mke2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-###########################################################################
-# Build tune2fs
-#
-tune2fs_src_files := \
-       tune2fs.c \
-       util.c
-
-tune2fs_c_includes := \
-       external/e2fsprogs/e2fsck
-
-tune2fs_cflags := -O2 -g -W -Wall -DNO_RECOVERY
-
-tune2fs_shared_libraries := \
-       libext2fs \
-       libext2_com_err \
-       libext2_blkid \
-       libext2_quota \
-       libext2_uuid \
-       libext2_e2p
-
-tune2fs_system_shared_libraries := libc
-
-
-tune2fs_static_libraries := \
-       libext2_com_err \
-       libext2_blkid \
-       libext2_quota \
-       libext2_uuid_static \
-       libext2_e2p \
-       libext2fs
-
-tune2fs_system_static_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(tune2fs_src_files)
-LOCAL_C_INCLUDES := $(tune2fs_c_includes)
-LOCAL_CFLAGS := $(tune2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(tune2fs_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(tune2fs_system_shared_libraries)
-LOCAL_MODULE := tune2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(tune2fs_src_files)
-LOCAL_C_INCLUDES := $(tune2fs_c_includes)
-LOCAL_CFLAGS := $(tune2fs_cflags)
-LOCAL_STATIC_LIBRARIES := $(tune2fs_static_libraries) $(tune2fs_system_static_libraries)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE := tune2fs_static
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(tune2fs_src_files)
-LOCAL_C_INCLUDES := $(tune2fs_c_includes)
-LOCAL_CFLAGS := $(tune2fs_cflags) -DBUILD_AS_LIB
-LOCAL_STATIC_LIBRARIES := $(tune2fs_static_libraries) $(tune2fs_system_static_libraries)
-LOCAL_MODULE := libtune2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(tune2fs_src_files)
-LOCAL_C_INCLUDES := $(tune2fs_c_includes)
-LOCAL_CFLAGS := $(tune2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(tune2fs_shared_libraries))
-LOCAL_MODULE := tune2fs_host
-LOCAL_MODULE_STEM := tune2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build badblocks
-#
-include $(CLEAR_VARS)
-
-badblocks_src_files := \
-       badblocks.c
-
-badblocks_c_includes :=
-
-badblocks_cflags := -O2 -g -W -Wall
-
-badblocks_shared_libraries := \
-       libext2fs \
-       libext2_com_err \
-       libext2_uuid \
-       libext2_blkid \
-       libext2_e2p
-
-badblocks_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(badblocks_src_files)
-LOCAL_C_INCLUDES := $(badblocks_c_includes)
-LOCAL_CFLAGS := $(badblocks_cflags)
-LOCAL_SHARED_LIBRARIES := $(badblocks_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(badblocks_system_shared_libraries)
-LOCAL_MODULE := badblocks
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(badblocks_src_files)
-LOCAL_C_INCLUDES := $(badblocks_c_includes)
-LOCAL_CFLAGS := $(badblocks_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(badblocks_shared_libraries))
-LOCAL_MODULE := badblocks_host
-LOCAL_MODULE_STEM := badblocks
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build chattr
-#
-include $(CLEAR_VARS)
-
-chattr_src_files := \
-       chattr.c
-
-chattr_c_includes := \
-       external/e2fsprogs/lib
-
-chattr_cflags := -O2 -g -W -Wall
-
-chattr_shared_libraries := \
-       libext2_com_err \
-       libext2_e2p
-
-chattr_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(chattr_src_files)
-LOCAL_C_INCLUDES := $(chattr_c_includes)
-LOCAL_CFLAGS := $(chattr_cflags)
-LOCAL_SHARED_LIBRARIES := $(chattr_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(chattr_system_shared_libraries)
-LOCAL_MODULE := chattr
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(chattr_src_files)
-LOCAL_C_INCLUDES := $(chattr_c_includes)
-LOCAL_CFLAGS := $(chattr_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(chattr_shared_libraries))
-LOCAL_MODULE := chattr_host
-LOCAL_MODULE_STEM := chattr
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build lsattr
-#
-include $(CLEAR_VARS)
-
-lsattr_src_files := \
-       lsattr.c
-
-lsattr_c_includes := \
-       external/e2fsprogs/lib
-
-lsattr_cflags := -O2 -g -W -Wall
-
-lsattr_shared_libraries := \
-       libext2_com_err \
-       libext2_e2p
-
-lsattr_system_shared_libraries := libc
-
-lsattr_static_libraries := \
-       libext2_com_err \
-       libext2_e2p
-
-lsattr_system_static_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(lsattr_src_files)
-LOCAL_C_INCLUDES := $(lsattr_c_includes)
-LOCAL_CFLAGS := $(lsattr_cflags)
-LOCAL_SHARED_LIBRARIES := $(lsattr_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(lsattr_system_shared_libraries)
-LOCAL_MODULE := lsattr
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(lsattr_src_files)
-LOCAL_C_INCLUDES := $(lsattr_c_includes)
-LOCAL_CFLAGS := $(lsattr_cflags)
-LOCAL_STATIC_LIBRARIES := $(lsattr_static_libraries) $(lsattr_system_static_libraries)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE := lsattr_static
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(lsattr_src_files)
-LOCAL_C_INCLUDES := $(lsattr_c_includes)
-LOCAL_CFLAGS := $(lsattr_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(lsattr_shared_libraries))
-LOCAL_MODULE := lsattr_host
-LOCAL_MODULE_STEM := lsattr
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build blkid
-#
-include $(CLEAR_VARS)
-
-blkid_src_files := \
-    blkid.c
-
-blkid_c_includes :=
-
-blkid_cflags := -O2 -g -W -Wall
-
-blkid_shared_libraries := \
-    libext2fs \
-    libext2_blkid \
-    libext2_com_err \
-    libext2_e2p
-
-blkid_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(blkid_src_files)
-LOCAL_C_INCLUDES := $(blkid_c_includes)
-LOCAL_CFLAGS := $(blkid_cflags)
-LOCAL_SHARED_LIBRARIES := $(blkid_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(blkid_system_shared_libraries)
-LOCAL_MODULE := blkid
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-#########################################################################
-# Build e4crypt
-e4crypt_src_files := e4crypt.c
-
-e4crypt_c_includes := \
-       external/e2fsprogs/lib
-
-e4crypt_cflags := -O2 -g -W -Wall
-
-e4crypt_shared_libraries := libext2fs libext2_uuid
-
-e4crypt_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e4crypt_src_files)
-LOCAL_C_INCLUDES := $(e4crypt_c_includes)
-LOCAL_CFLAGS := $(e4crypt_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(e4crypt_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(e4crypt_shared_libraries)
-LOCAL_MODULE := e4crypt
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e4crypt_src_files)
-LOCAL_C_INCLUDES := $(e4crypt_c_includes)
-LOCAL_CFLAGS := $(e4crypt_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(e4crypt_shared_libraries))
-LOCAL_MODULE := e4crypt_host
-LOCAL_MODULE_STEM := e4crypt
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_HOST_OS := linux
-
-include $(BUILD_HOST_EXECUTABLE)
-
-###########################################################################
-# Build e2image
-#
-e2image_src_files := \
-       e2image.c
-
-e2image_c_includes := \
-       external/e2fsprogs/lib
-
-e2image_cflags := -O2 -g -W -Wall
-
-e2image_shared_libraries := \
-       libext2fs \
-       libext2_blkid \
-       libext2_com_err \
-       libext2_quota
-
-e2image_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2image_src_files)
-LOCAL_C_INCLUDES := $(e2image_c_includes)
-mke2fs_c_includesLOCAL_CFLAGS := $(e2image_cflags)
-LOCAL_SHARED_LIBRARIES := $(e2image_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(e2image_system_shared_libraries)
-LOCAL_MODULE := e2image
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2image_src_files)
-LOCAL_C_INCLUDES := $(e2image_c_includes)
-LOCAL_CFLAGS := $(e2image_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(e2image_shared_libraries))
-LOCAL_MODULE := e2image_host
-LOCAL_MODULE_STEM := e2image
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
index a309aaaac7ba9c4d5be28efcd4430c7be8aec61f..f696d13a8b58518b167fbbdb66d00debca780233 100644 (file)
@@ -252,7 +252,7 @@ base_device: base_device.c
        $(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(srcdir)/base_device.c \
                -DDEBUG -o base_device $(SYSLIBS)
 
-check:: base_device
+fullcheck check:: base_device
        ./base_device < $(srcdir)/base_device.tst > base_device.out
        cmp $(srcdir)/base_device.tst base_device.out
 
index 8ce3fafaacc32ef33a4653c86649e573cc136275..8f7445d027349c0449dc08f48fcac8c031337a77 100644 (file)
@@ -683,10 +683,31 @@ out:
        return retval;
 }
 
+struct file_info {
+       char *path;
+       size_t path_len;
+       size_t path_max_len;
+};
+
+static errcode_t path_append(struct file_info *target, const char *file)
+{
+       if (strlen(file) + target->path_len + 1 > target->path_max_len) {
+               target->path_max_len *= 2;
+               target->path = realloc(target->path, target->path_max_len);
+               if (!target->path)
+                       return EXT2_ET_NO_MEMORY;
+       }
+       target->path_len += sprintf(target->path + target->path_len, "/%s",
+                                   file);
+       return 0;
+}
+
 /* Copy files from source_dir to fs */
 static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
                               const char *source_dir, ext2_ino_t root,
-                              struct hdlinks_s *hdlinks)
+                              struct hdlinks_s *hdlinks,
+                              struct file_info *target,
+                              struct fs_ops_callbacks *fs_callbacks)
 {
        const char      *name;
        DIR             *dh;
@@ -698,6 +719,7 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
        errcode_t       retval = 0;
        int             read_cnt;
        int             hdlink;
+       size_t          cur_dir_path_len;
 
        if (chdir(source_dir) < 0) {
                retval = errno;
@@ -745,6 +767,19 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
                                save_inode = 1;
                }
 
+               cur_dir_path_len = target->path_len;
+               retval = path_append(target, name);
+               if (retval)
+                       return retval;
+
+               if (fs_callbacks && fs_callbacks->create_new_inode) {
+                       retval = fs_callbacks->create_new_inode(fs,
+                               target->path, name, parent_ino, root,
+                               st.st_mode & S_IFMT);
+                       if (retval)
+                               goto out;
+               }
+
                switch(st.st_mode & S_IFMT) {
                case S_IFCHR:
                case S_IFBLK:
@@ -822,7 +857,8 @@ find_lnf:
                                        goto out;
                        }
                        /* Populate the dir recursively*/
-                       retval = __populate_fs(fs, ino, name, root, hdlinks);
+                       retval = __populate_fs(fs, ino, name, root, hdlinks,
+                                              target, fs_callbacks);
                        if (retval)
                                goto out;
                        if (chdir("..")) {
@@ -858,6 +894,14 @@ find_lnf:
                        goto out;
                }
 
+               if (fs_callbacks && fs_callbacks->end_create_new_inode) {
+                       retval = fs_callbacks->end_create_new_inode(fs,
+                               target->path, name, parent_ino, root,
+                               st.st_mode & S_IFMT);
+                       if (retval)
+                               goto out;
+               }
+
                /* Save the hardlink ino */
                if (save_inode) {
                        /*
@@ -883,6 +927,8 @@ find_lnf:
                        hdlinks->hdl[hdlinks->count].dst_ino = ino;
                        hdlinks->count++;
                }
+               target->path_len = cur_dir_path_len;
+               target->path[target->path_len] = 0;
        }
 
 out:
@@ -890,9 +936,11 @@ out:
        return retval;
 }
 
-errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
-                     const char *source_dir, ext2_ino_t root)
+errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
+                      const char *source_dir, ext2_ino_t root,
+                      struct fs_ops_callbacks *fs_callbacks)
 {
+       struct file_info file_info;
        struct hdlinks_s hdlinks;
        errcode_t retval;
 
@@ -910,8 +958,20 @@ errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
                return retval;
        }
 
-       retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks);
+       file_info.path_len = 0;
+       file_info.path_max_len = 255;
+       file_info.path = calloc(file_info.path_max_len, 1);
 
+       retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks,
+                              &file_info, fs_callbacks);
+
+       free(file_info.path);
        free(hdlinks.hdl);
        return retval;
 }
+
+errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
+                     const char *source_dir, ext2_ino_t root)
+{
+       return populate_fs2(fs, parent_ino, source_dir, root, NULL);
+}
index cf49df2ee7e808fce3620b3959b72ba88b9411c8..17309c68452895c3ed12ffc397ff42d36527975a 100644 (file)
@@ -24,9 +24,21 @@ struct hdlinks_s
 
 #define HDLINK_CNT     (4)
 
+struct fs_ops_callbacks {
+       errcode_t (* create_new_inode)(ext2_filsys fs, const char *target_path,
+               const char *name, ext2_ino_t parent_ino, ext2_ino_t root,
+               mode_t mode);
+       errcode_t (* end_create_new_inode)(ext2_filsys fs,
+               const char *target_path, const char *name,
+               ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
+};
+
 /* For populating the filesystem */
 extern errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
                             const char *source_dir, ext2_ino_t root);
+extern errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
+                             const char *source_dir, ext2_ino_t root,
+                             struct fs_ops_callbacks *fs_callbacks);
 extern errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd,
                                   const char *name, struct stat *st);
 extern errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd,
index 90acb7e115539c9b8ec86f87b52f1b1c029bdf20..b315263db7b780bb4493aecc7ca95fb52f055f1f 100644 (file)
 extern char *optarg;
 extern int optind;
 #endif
+#if defined(HAVE_EXT2_IOCTLS) && !defined(DEBUGFS)
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <limits.h>
+#endif
 
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fs.h"
 #include "e2freefrag.h"
 
+#if defined(HAVE_EXT2_IOCTLS) && !defined(DEBUGFS)
+# ifdef HAVE_LINUX_FSMAP_H
+#  include <linux/fsmap.h>
+# endif
+# include "fsmap.h"
+#endif
+
 static void usage(const char *prog)
 {
        fprintf(stderr, "usage: %s [-c chunksize in kb] [-h] "
@@ -143,8 +157,97 @@ static void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
                update_chunk_stats(info, last_chunk_size);
 }
 
-static errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info,
-                               FILE *f)
+#if defined(HAVE_EXT2_IOCTLS) && !defined(DEBUGFS)
+# define FSMAP_EXTENTS 1024
+static int scan_online(ext2_filsys fs, struct chunk_info *info)
+{
+       struct fsmap_head *fsmap;
+       struct fsmap *extent;
+       struct fsmap *p;
+       char mntpoint[PATH_MAX + 1];
+       errcode_t retval;
+       int mount_flags;
+       int fd;
+       int ret;
+       int i;
+
+       /* Try to open the mountpoint for a live query. */
+       retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
+                                         mntpoint, PATH_MAX);
+       if (retval) {
+               com_err(fs->device_name, retval, "while checking mount status");
+               return 0;
+       }
+       if (!mount_flags & EXT2_MF_MOUNTED)
+               return 0;
+       fd = open(mntpoint, O_RDONLY);
+       if (fd < 0) {
+               com_err(mntpoint, errno, "while opening mount point");
+               return 0;
+       }
+
+       fsmap = malloc(fsmap_sizeof(FSMAP_EXTENTS));
+       if (!fsmap) {
+               com_err(fs->device_name, errno, "while allocating memory");
+               return 0;
+       }
+
+       memset(fsmap, 0, sizeof(*fsmap));
+       fsmap->fmh_count = FSMAP_EXTENTS;
+       fsmap->fmh_keys[1].fmr_device = UINT_MAX;
+       fsmap->fmh_keys[1].fmr_physical = ULLONG_MAX;
+       fsmap->fmh_keys[1].fmr_owner = ULLONG_MAX;
+       fsmap->fmh_keys[1].fmr_offset = ULLONG_MAX;
+       fsmap->fmh_keys[1].fmr_flags = UINT_MAX;
+
+       /* Fill the extent histogram with live data */
+       while (1) {
+               ret = ioctl(fd, FS_IOC_GETFSMAP, fsmap);
+               if (ret < 0) {
+                       com_err(fs->device_name, errno, "while calling fsmap");
+                       free(fsmap);
+                       return 0;
+               }
+
+               /* No more extents to map, exit */
+               if (!fsmap->fmh_entries)
+                       break;
+
+               for (i = 0, extent = fsmap->fmh_recs;
+                    i < fsmap->fmh_entries;
+                    i++, extent++) {
+                       if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
+                           extent->fmr_owner != FMR_OWN_FREE)
+                               continue;
+                       update_chunk_stats(info,
+                                          extent->fmr_length / fs->blocksize);
+               }
+
+               p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
+               if (p->fmr_flags & FMR_OF_LAST)
+                       break;
+               fsmap_advance(fsmap);
+       }
+
+       return 1;
+}
+#else
+# define scan_online(fs, info) (0)
+#endif /* HAVE_EXT2_IOCTLS */
+
+static errcode_t scan_offline(ext2_filsys fs, struct chunk_info *info)
+{
+       errcode_t retval;
+
+       retval = ext2fs_read_block_bitmap(fs);
+       if (retval)
+               return retval;
+       scan_block_bitmap(fs, info);
+       return 0;
+}
+
+static errcode_t dump_chunk_info(ext2_filsys fs, struct chunk_info *info,
+                                FILE *f)
 {
        unsigned long total_chunks;
        const char *unitp = "KMGTPEZY";
@@ -152,8 +255,6 @@ static errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info,
        unsigned long start = 0, end;
        int i, retval = 0;
 
-       scan_block_bitmap(fs, info);
-
        fprintf(f, "Total blocks: %llu\nFree blocks: %u (%0.1f%%)\n",
                ext2fs_blocks_count(fs->super), fs->super->s_free_blocks_count,
                (double)fs->super->s_free_blocks_count * 100 /
@@ -228,18 +329,20 @@ static void collect_info(ext2_filsys fs, struct chunk_info *chunk_info, FILE *f)
        fprintf(f, "Device: %s\n", fs->device_name);
        fprintf(f, "Blocksize: %u bytes\n", fs->blocksize);
 
-       retval = ext2fs_read_block_bitmap(fs);
+       init_chunk_info(fs, chunk_info);
+       if (!scan_online(fs, chunk_info)) {
+               init_chunk_info(fs, chunk_info);
+               retval = scan_offline(fs, chunk_info);
+       }
        if (retval) {
                com_err(fs->device_name, retval, "while reading block bitmap");
                close_device(fs->device_name, fs);
                exit(1);
        }
 
-       init_chunk_info(fs, chunk_info);
-
-       retval = get_chunk_info(fs, chunk_info, f);
+       retval = dump_chunk_info(fs, chunk_info, f);
        if (retval) {
-               com_err(fs->device_name, retval, "while collecting chunk info");
+               com_err(fs->device_name, retval, "while dumping chunk info");
                 close_device(fs->device_name, fs);
                exit(1);
        }
diff --git a/misc/fsmap.h b/misc/fsmap.h
new file mode 100644 (file)
index 0000000..e9590aa
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 Oracle.
+ * All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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 License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef FSMAP_H_
+#define FSMAP_H_
+
+/* FS_IOC_GETFSMAP ioctl definitions */
+#ifndef FS_IOC_GETFSMAP
+struct fsmap {
+       __u32           fmr_device;     /* device id */
+       __u32           fmr_flags;      /* mapping flags */
+       __u64           fmr_physical;   /* device offset of segment */
+       __u64           fmr_owner;      /* owner id */
+       __u64           fmr_offset;     /* file offset of segment */
+       __u64           fmr_length;     /* length of segment */
+       __u64           fmr_reserved[3];        /* must be zero */
+};
+
+struct fsmap_head {
+       __u32           fmh_iflags;     /* control flags */
+       __u32           fmh_oflags;     /* output flags */
+       __u32           fmh_count;      /* # of entries in array incl. input */
+       __u32           fmh_entries;    /* # of entries filled in (output). */
+       __u64           fmh_reserved[6];        /* must be zero */
+
+       struct fsmap    fmh_keys[2];    /* low and high keys for the mapping search */
+       struct fsmap    fmh_recs[];     /* returned records */
+};
+
+/* Size of an fsmap_head with room for nr records. */
+static inline size_t
+fsmap_sizeof(
+       unsigned int    nr)
+{
+       return sizeof(struct fsmap_head) + nr * sizeof(struct fsmap);
+}
+
+/* Start the next fsmap query at the end of the current query results. */
+static inline void
+fsmap_advance(
+       struct fsmap_head       *head)
+{
+       head->fmh_keys[0] = head->fmh_recs[head->fmh_entries - 1];
+}
+
+/*     fmh_iflags values - set by FS_IOC_GETFSMAP caller in the header. */
+/* no flags defined yet */
+#define FMH_IF_VALID           0
+
+/*     fmh_oflags values - returned in the header segment only. */
+#define FMH_OF_DEV_T           0x1     /* fmr_device values will be dev_t */
+
+/*     fmr_flags values - returned for each non-header segment */
+#define FMR_OF_PREALLOC                0x1     /* segment = unwritten pre-allocation */
+#define FMR_OF_ATTR_FORK       0x2     /* segment = attribute fork */
+#define FMR_OF_EXTENT_MAP      0x4     /* segment = extent map */
+#define FMR_OF_SHARED          0x8     /* segment = shared with another file */
+#define FMR_OF_SPECIAL_OWNER   0x10    /* owner is a special value */
+#define FMR_OF_LAST            0x20    /* segment is the last in the FS */
+
+/* Each FS gets to define its own special owner codes. */
+#define FMR_OWNER(type, code)  (((__u64)type << 32) | \
+                                ((__u64)code & 0xFFFFFFFFULL))
+#define FMR_OWNER_TYPE(owner)  ((__u32)((__u64)owner >> 32))
+#define FMR_OWNER_CODE(owner)  ((__u32)(((__u64)owner & 0xFFFFFFFFULL)))
+#define FMR_OWN_FREE           FMR_OWNER(0, 1) /* free space */
+#define FMR_OWN_UNKNOWN                FMR_OWNER(0, 2) /* unknown owner */
+#define FMR_OWN_METADATA       FMR_OWNER(0, 3) /* metadata */
+
+#define FS_IOC_GETFSMAP                _IOWR('X', 59, struct fsmap_head)
+#endif /* FS_IOC_GETFSMAP */
+
+#endif
index b5897685c4662b16a21f7a3d2b9d8864493ac93f..9435e428c823086f81fed7bd1cf47310c9374d2e 100644 (file)
@@ -863,8 +863,9 @@ static int op_readlink(const char *path, char *buf, size_t len)
        len--;
        if (inode.i_size < len)
                len = inode.i_size;
-       if (ext2fs_inode_data_blocks2(fs, &inode) ||
-           (inode.i_flags & EXT4_INLINE_DATA_FL)) {
+       if (ext2fs_is_fast_symlink(&inode))
+               memcpy(buf, (char *)inode.i_block, len);
+       else {
                /* big/inline symlink */
 
                err = ext2fs_file_open(fs, ino, 0, &file);
@@ -888,9 +889,7 @@ out2:
                        ret = translate_error(fs, ino, err);
                        goto out;
                }
-       } else
-               /* inline symlink */
-               memcpy(buf, (char *)inode.i_block, len);
+       }
        buf[len] = 0;
 
        if (fs_writeable(fs)) {
@@ -2654,12 +2653,6 @@ static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
                goto out3;
        }
 
-       err = ext2fs_xattrs_write(h);
-       if (err) {
-               ret = translate_error(fs, ino, err);
-               goto out3;
-       }
-
        ret = update_ctime(fs, ino, NULL);
 out3:
        if (cvalue != value)
@@ -2726,12 +2719,6 @@ static int op_removexattr(const char *path, const char *key)
                goto out2;
        }
 
-       err = ext2fs_xattrs_write(h);
-       if (err) {
-               ret = translate_error(fs, ino, err);
-               goto out2;
-       }
-
        ret = update_ctime(fs, ino, NULL);
 out2:
        err = ext2fs_xattrs_close(&h);
@@ -3786,6 +3773,7 @@ int main(int argc, char *argv[])
        global_fs->priv_data = &fctx;
 
        ret = 3;
+
        if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
                if (!fctx.ro) {
                        printf(_("%s: recovering journal\n"), fctx.device);
index b8d078a0a6c48c093a5465202f06f2a3a9888ef3..85d88edc237536294551e12d56d4e380a4196ddc 100644 (file)
@@ -113,6 +113,9 @@ char **fs_types;
 const char *src_root_dir;  /* Copy files from the specified directory */
 static char *undo_file;
 
+static int android_sparse_file; /* -E android_sparse */
+static char *android_sparse_params;
+
 static profile_t       profile;
 
 static int sys_page_size = 4096;
@@ -553,7 +556,7 @@ static void zap_sector(ext2_filsys fs, int sect, int nsect)
        int retval;
        unsigned int *magic;
 
-       buf = malloc(512*nsect);
+       buf = calloc(512, nsect);
        if (!buf) {
                printf(_("Out of memory erasing sectors %d-%d\n"),
                       sect, sect + nsect - 1);
@@ -1026,6 +1029,8 @@ static void parse_extended_opts(struct ext2_super_block *param,
                                badopt = token;
                                continue;
                        }
+               } else if (!strcmp(token, "android_sparse")) {
+                       android_sparse_file = 1;
                } else {
                        r_usage++;
                        badopt = token;
@@ -1077,11 +1082,13 @@ static __u32 ok_features[3] = {
                EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
                EXT2_FEATURE_INCOMPAT_META_BG|
                EXT4_FEATURE_INCOMPAT_FLEX_BG|
+               EXT4_FEATURE_INCOMPAT_EA_INODE|
                EXT4_FEATURE_INCOMPAT_MMP |
                EXT4_FEATURE_INCOMPAT_64BIT|
                EXT4_FEATURE_INCOMPAT_INLINE_DATA|
                EXT4_FEATURE_INCOMPAT_ENCRYPT |
-               EXT4_FEATURE_INCOMPAT_CSUM_SEED,
+               EXT4_FEATURE_INCOMPAT_CSUM_SEED |
+               EXT4_FEATURE_INCOMPAT_LARGEDIR,
        /* R/O compat */
        EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
                EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -1985,6 +1992,7 @@ profile_error:
                ext2fs_clear_feature_filetype(&fs_param);
                ext2fs_clear_feature_huge_file(&fs_param);
                ext2fs_clear_feature_metadata_csum(&fs_param);
+               ext2fs_clear_feature_ea_inode(&fs_param);
        }
        edit_feature(fs_features ? fs_features : tmp,
                     &fs_param.s_feature_compat);
@@ -2010,6 +2018,11 @@ profile_error:
                                                "metadata_csum feature.\n"));
                        exit(1);
                }
+               if (ext2fs_has_feature_ea_inode(&fs_param)) {
+                       fprintf(stderr, "%s", _("The HURD does not support the "
+                                               "ea_inode feature.\n"));
+                       exit(1);
+               }
        }
 
        /* Get the hardware sector sizes, if available */
@@ -2827,7 +2840,21 @@ int main (int argc, char *argv[])
         */
        if (!quiet)
                flags |= EXT2_FLAG_PRINT_PROGRESS;
-       retval = ext2fs_initialize(device_name, flags, &fs_param, io_ptr, &fs);
+       if (android_sparse_file) {
+               android_sparse_params = malloc(PATH_MAX + 32);
+               if (!android_sparse_params) {
+                       com_err(program_name, ENOMEM, "%s",
+                               _("in malloc for android_sparse_params"));
+                       exit(1);
+               }
+               snprintf(android_sparse_params, PATH_MAX + 32, "%s:%u:%u",
+                        device_name, fs_param.s_blocks_count,
+                        1024 << fs_param.s_log_block_size);
+               retval = ext2fs_initialize(android_sparse_params, flags,
+                                          &fs_param, sparse_io_manager, &fs);
+       } else
+               retval = ext2fs_initialize(device_name, flags, &fs_param,
+                                          io_ptr, &fs);
        if (retval) {
                com_err(device_name, retval, "%s",
                        _("while setting up superblock"));
index 85435674d5ef09611735aa2cf3f4bfcd654d4742..9b53dc28e9cb90884b1c16edf8d43ade7564ec1b 100644 (file)
@@ -153,10 +153,12 @@ static __u32 ok_features[3] = {
        EXT2_FEATURE_INCOMPAT_FILETYPE |
                EXT3_FEATURE_INCOMPAT_EXTENTS |
                EXT4_FEATURE_INCOMPAT_FLEX_BG |
+               EXT4_FEATURE_INCOMPAT_EA_INODE|
                EXT4_FEATURE_INCOMPAT_MMP |
                EXT4_FEATURE_INCOMPAT_64BIT |
                EXT4_FEATURE_INCOMPAT_ENCRYPT |
-               EXT4_FEATURE_INCOMPAT_CSUM_SEED,
+               EXT4_FEATURE_INCOMPAT_CSUM_SEED |
+               EXT4_FEATURE_INCOMPAT_LARGEDIR,
        /* R/O compat */
        EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
                EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -716,115 +718,224 @@ static errcode_t rewrite_directory(ext2_filsys fs, ext2_ino_t dir,
        return ctx.errcode;
 }
 
+/*
+ * Context information that does not change across rewrite_one_inode()
+ * invocations.
+ */
+struct rewrite_context {
+       ext2_filsys fs;
+       struct ext2_inode *zero_inode;
+       char *ea_buf;
+       int inode_size;
+};
+
+#define fatal_err(code, args...)               \
+       do {                                    \
+               com_err(__func__, code, args);  \
+               exit(1);                        \
+       } while (0);
+
+static void update_ea_inode_hash(struct rewrite_context *ctx, ext2_ino_t ino,
+                                struct ext2_inode *inode)
+{
+       errcode_t retval;
+       ext2_file_t file;
+       __u32 hash;
+
+       retval = ext2fs_file_open(ctx->fs, ino, 0, &file);
+       if (retval)
+               fatal_err(retval, "open ea_inode");
+       retval = ext2fs_file_read(file, ctx->ea_buf, inode->i_size,
+                                 NULL);
+       if (retval)
+               fatal_err(retval, "read ea_inode");
+       retval = ext2fs_file_close(file);
+       if (retval)
+               fatal_err(retval, "close ea_inode");
+
+       hash = ext2fs_crc32c_le(ctx->fs->csum_seed, ctx->ea_buf, inode->i_size);
+       ext2fs_set_ea_inode_hash(inode, hash);
+}
+
+static int update_xattr_entry_hashes(ext2_filsys fs,
+                                    struct ext2_ext_attr_entry *entry,
+                                    struct ext2_ext_attr_entry *end)
+{
+       int modified = 0;
+       errcode_t retval;
+
+       while (entry < end && !EXT2_EXT_IS_LAST_ENTRY(entry)) {
+               if (entry->e_value_inum) {
+                       retval = ext2fs_ext_attr_hash_entry2(fs, entry, NULL,
+                                                            &entry->e_hash);
+                       if (retval)
+                               fatal_err(retval, "hash ea_inode entry");
+                       modified = 1;
+               }
+               entry = EXT2_EXT_ATTR_NEXT(entry);
+       }
+       return modified;
+}
+
+static void update_inline_xattr_hashes(struct rewrite_context *ctx,
+                                      struct ext2_inode_large *inode)
+{
+       struct ext2_ext_attr_entry *start, *end;
+       __u32 *ea_magic;
+
+       if (inode->i_extra_isize == 0)
+               return;
+
+       if (inode->i_extra_isize & 3 ||
+           inode->i_extra_isize > ctx->inode_size - EXT2_GOOD_OLD_INODE_SIZE)
+               fatal_err(EXT2_ET_INODE_CORRUPTED, "bad i_extra_isize")
+
+       ea_magic = (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
+                               inode->i_extra_isize);
+       if (*ea_magic != EXT2_EXT_ATTR_MAGIC)
+               return;
+
+       start = (struct ext2_ext_attr_entry *)(ea_magic + 1);
+       end = (struct ext2_ext_attr_entry *)((char *)inode + ctx->inode_size);
+
+       update_xattr_entry_hashes(ctx->fs, start, end);
+}
+
+static void update_block_xattr_hashes(struct rewrite_context *ctx,
+                                     void *block_buf)
+{
+       struct ext2_ext_attr_header *header;
+       struct ext2_ext_attr_entry *start, *end;
+
+       header = (struct ext2_ext_attr_header *)block_buf;
+       if (header->h_magic != EXT2_EXT_ATTR_MAGIC)
+               return;
+
+       start = (struct ext2_ext_attr_entry *)(header+1);
+       end = (struct ext2_ext_attr_entry *)(block_buf + ctx->fs->blocksize);
+
+       if (update_xattr_entry_hashes(ctx->fs, start, end))
+               ext2fs_ext_attr_block_rehash(header, end);
+}
+
+static void rewrite_one_inode(struct rewrite_context *ctx, ext2_ino_t ino,
+                             struct ext2_inode *inode)
+{
+       blk64_t file_acl_block;
+       errcode_t retval;
+
+       if (!ext2fs_test_inode_bitmap2(ctx->fs->inode_map, ino)) {
+               if (!memcmp(inode, ctx->zero_inode, ctx->inode_size))
+                       return;
+               memset(inode, 0, ctx->inode_size);
+       }
+
+       if (inode->i_flags & EXT4_EA_INODE_FL)
+               update_ea_inode_hash(ctx, ino, inode);
+
+       if (ctx->inode_size != EXT2_GOOD_OLD_INODE_SIZE)
+               update_inline_xattr_hashes(ctx,
+                                          (struct ext2_inode_large *)inode);
+
+       retval = ext2fs_write_inode_full(ctx->fs, ino, inode, ctx->inode_size);
+       if (retval)
+               fatal_err(retval, "while writing inode");
+
+       retval = rewrite_extents(ctx->fs, ino, inode);
+       if (retval)
+               fatal_err(retval, "while rewriting extents");
+
+       if (LINUX_S_ISDIR(inode->i_mode) &&
+           ext2fs_inode_has_valid_blocks2(ctx->fs, inode)) {
+               retval = rewrite_directory(ctx->fs, ino, inode);
+               if (retval)
+                       fatal_err(retval, "while rewriting directories");
+       }
+
+       file_acl_block = ext2fs_file_acl_block(ctx->fs, inode);
+       if (!file_acl_block)
+               return;
+
+       retval = ext2fs_read_ext_attr3(ctx->fs, file_acl_block, ctx->ea_buf,
+                                      ino);
+       if (retval)
+               fatal_err(retval, "while rewriting extended attribute");
+
+       update_block_xattr_hashes(ctx, ctx->ea_buf);
+       retval = ext2fs_write_ext_attr3(ctx->fs, file_acl_block, ctx->ea_buf,
+                                       ino);
+       if (retval)
+               fatal_err(retval, "while rewriting extended attribute");
+}
+
 /*
  * Forcibly set checksums in all inodes.
  */
 static void rewrite_inodes(ext2_filsys fs)
 {
-       int length = EXT2_INODE_SIZE(fs->super);
-       struct ext2_inode *inode, *zero;
-       char            *ea_buf;
        ext2_inode_scan scan;
        errcode_t       retval;
        ext2_ino_t      ino;
-       blk64_t         file_acl_block;
-       int             inode_dirty;
+       struct ext2_inode *inode;
+       int pass;
+       struct rewrite_context ctx = {
+               .fs = fs,
+               .inode_size = EXT2_INODE_SIZE(fs->super),
+       };
 
        if (fs->super->s_creator_os == EXT2_OS_HURD)
                return;
 
-       retval = ext2fs_open_inode_scan(fs, 0, &scan);
-       if (retval) {
-               com_err("set_csum", retval, "while opening inode scan");
-               exit(1);
-       }
-
-       retval = ext2fs_get_mem(length, &inode);
-       if (retval) {
-               com_err("set_csum", retval, "while allocating memory");
-               exit(1);
-       }
-
-       retval = ext2fs_get_memzero(length, &zero);
-       if (retval) {
-               com_err("set_csum", retval, "while allocating memory");
-               exit(1);
-       }
+       retval = ext2fs_get_mem(ctx.inode_size, &inode);
+       if (retval)
+               fatal_err(retval, "while allocating memory");
 
-       retval = ext2fs_get_mem(fs->blocksize, &ea_buf);
-       if (retval) {
-               com_err("set_csum", retval, "while allocating memory");
-               exit(1);
-       }
+       retval = ext2fs_get_memzero(ctx.inode_size, &ctx.zero_inode);
+       if (retval)
+               fatal_err(retval, "while allocating memory");
 
-       do {
-               retval = ext2fs_get_next_inode_full(scan, &ino, inode, length);
-               if (retval) {
-                       com_err("set_csum", retval, "while getting next inode");
-                       exit(1);
-               }
-               if (!ino)
-                       break;
-               if (ext2fs_test_inode_bitmap2(fs->inode_map, ino)) {
-                       inode_dirty = 1;
-               } else {
-                       if (memcmp(inode, zero, length) != 0) {
-                               memset(inode, 0, length);
-                               inode_dirty = 1;
-                       } else {
-                               inode_dirty = 0;
-                       }
-               }
+       retval = ext2fs_get_mem(64 * 1024, &ctx.ea_buf);
+       if (retval)
+               fatal_err(retval, "while allocating memory");
 
-               if (inode_dirty) {
-                       retval = ext2fs_write_inode_full(fs, ino, inode,
-                                                        length);
-                       if (retval) {
-                               com_err("set_csum", retval, "while writing "
-                                       "inode");
-                               exit(1);
-                       }
-               }
+       /*
+        * Extended attribute inodes have a lookup hash that needs to be
+        * recalculated with the new csum_seed. Other inodes referencing xattr
+        * inodes need this value to be up to date. That's why we do two passes:
+        *
+        * pass 1: update xattr inodes to update their lookup hash as well as
+        *         other checksums.
+        *
+        * pass 2: go over other inodes to update their checksums.
+        */
+       if (ext2fs_has_feature_ea_inode(fs->super))
+               pass = 1;
+       else
+               pass = 2;
+       for (;pass <= 2; pass++) {
+               retval = ext2fs_open_inode_scan(fs, 0, &scan);
+               if (retval)
+                       fatal_err(retval, "while opening inode scan");
 
-               retval = rewrite_extents(fs, ino, inode);
-               if (retval) {
-                       com_err("rewrite_extents", retval,
-                               "while rewriting extents");
-                       exit(1);
-               }
+               do {
+                       retval = ext2fs_get_next_inode_full(scan, &ino, inode,
+                                                           ctx.inode_size);
+                       if (retval)
+                               fatal_err(retval, "while getting next inode");
+                       if (!ino)
+                               break;
 
-               if (LINUX_S_ISDIR(inode->i_mode) &&
-                   ext2fs_inode_has_valid_blocks2(fs, inode)) {
-                       retval = rewrite_directory(fs, ino, inode);
-                       if (retval) {
-                               com_err("rewrite_directory", retval,
-                                       "while rewriting directories");
-                               exit(1);
-                       }
-               }
+                       if (pass == 1 && (inode->i_flags & EXT4_EA_INODE_FL) ||
+                           pass == 2 && !(inode->i_flags & EXT4_EA_INODE_FL))
+                               rewrite_one_inode(&ctx, ino, inode);
+               } while (ino);
 
-               file_acl_block = ext2fs_file_acl_block(fs, inode);
-               if (!file_acl_block)
-                       continue;
-               retval = ext2fs_read_ext_attr3(fs, file_acl_block, ea_buf, ino);
-               if (retval) {
-                       com_err("rewrite_eablock", retval,
-                               "while rewriting extended attribute");
-                       exit(1);
-               }
-               retval = ext2fs_write_ext_attr3(fs, file_acl_block, ea_buf,
-                                               ino);
-               if (retval) {
-                       com_err("rewrite_eablock", retval,
-                               "while rewriting extended attribute");
-                       exit(1);
-               }
-       } while (ino);
+               ext2fs_close_inode_scan(scan);
+       }
 
-       ext2fs_free_mem(&zero);
+       ext2fs_free_mem(&ctx.zero_inode);
+       ext2fs_free_mem(&ctx.ea_buf);
        ext2fs_free_mem(&inode);
-       ext2fs_free_mem(&ea_buf);
-       ext2fs_close_inode_scan(scan);
 }
 
 static void rewrite_metadata_checksums(ext2_filsys fs)
@@ -837,11 +948,8 @@ static void rewrite_metadata_checksums(ext2_filsys fs)
        for (i = 0; i < fs->group_desc_count; i++)
                ext2fs_group_desc_csum_set(fs, i);
        retval = ext2fs_read_bitmaps(fs);
-       if (retval) {
-               com_err("rewrite_metadata_checksums", retval,
-                       "while reading bitmaps");
-               exit(1);
-       }
+       if (retval)
+               fatal_err(retval, "while reading bitmaps");
        rewrite_inodes(fs);
        ext2fs_mark_ib_dirty(fs);
        ext2fs_mark_bb_dirty(fs);
@@ -3133,8 +3241,9 @@ retry_open:
                }
 
                ext2fs_mark_super_dirty(fs);
-               if (ext2fs_has_feature_metadata_csum(fs->super) &&
-                   !ext2fs_has_feature_csum_seed(fs->super))
+               if (!ext2fs_has_feature_csum_seed(fs->super) &&
+                   (ext2fs_has_feature_metadata_csum(fs->super) ||
+                    ext2fs_has_feature_ea_inode(fs->super)))
                        rewrite_checksums = 1;
        }
 
index 2ae2f2a214d9efe2d5bba6a13be00194b2338895..eff37d33737d200424611ed29be6ace30f793adf 100644 (file)
@@ -270,7 +270,7 @@ uninstall-data-yes:
          done; \
        done
 
-check: all
+fullcheck check: all
 
 info dvi ps pdf html tags TAGS ctags CTAGS ID:
 
index bc1a744cad9c6db2bb00bc64df1ec4a44b522f7e..47e4ebdc9b1df41e010e34e8c5870baa268c659f 100644 (file)
@@ -45,7 +45,7 @@ my @translator_help = (
  "#.   %IM     <inode> -> i_mtime\n",
  "#.   %IF     <inode> -> i_faddr\n",
  "#.   %If     <inode> -> i_file_acl\n",
- "#.   %Id     <inode> -> i_dir_acl\n",
+ "#.   %Id     <inode> -> i_size_high\n",
  "#.   %Iu     <inode> -> i_uid\n",
  "#.   %Ig     <inode> -> i_gid\n",
  "#.   %It     <str>                   file type\n",
diff --git a/resize/Android.bp b/resize/Android.bp
new file mode 100644 (file)
index 0000000..6d3d321
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_binary {
+    name: "resize2fs",
+    host_supported: true,
+
+    srcs: [
+        "extent.c",
+        "resize2fs.c",
+        "main.c",
+        "online.c",
+        "sim_progress.c",
+        "resource_track.c",
+    ],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libext2_e2p",
+        "libext2_uuid",
+        "libext2_blkid",
+    ],
+    system_shared_libs: ["libc"],
+}
diff --git a/resize/Android.mk b/resize/Android.mk
deleted file mode 100644 (file)
index 12d6ab5..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-resize2fs_src_files := \
-       extent.c \
-       resize2fs.c \
-       main.c \
-       online.c \
-       sim_progress.c \
-       resource_track.c
-
-resize2fs_c_includes := external/e2fsprogs/lib
-
-resize2fs_cflags := -O2 -g -W -Wall
-
-resize2fs_shared_libraries := \
-       libext2fs \
-       libext2_com_err \
-       libext2_e2p \
-       libext2_uuid \
-       libext2_blkid
-
-resize2fs_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(resize2fs_src_files)
-LOCAL_C_INCLUDES := $(resize2fs_c_includes)
-LOCAL_CFLAGS := $(resize2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(resize2fs_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(resize2fs_system_shared_libraries)
-LOCAL_MODULE := resize2fs
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(resize2fs_src_files)
-LOCAL_C_INCLUDES := $(resize2fs_c_includes)
-LOCAL_CFLAGS := $(resize2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(resize2fs_shared_libraries))
-LOCAL_MODULE := resize2fs_host
-LOCAL_MODULE_STEM := resize2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
index 91c1a8ee0f6a2d310535281bf3b7a6820b693e18..51241827918b610f0367652e0bb7d15c51e0b69a 100644 (file)
@@ -94,7 +94,7 @@ uninstall:
 test_extent.out: test_extent $(srcdir)/test_extent.in
        $(TESTENV) ./test_extent < $(srcdir)/test_extent.in > test_extent.out
 
-check:: test_extent.out
+fullcheck check:: test_extent.out
        $(Q) if cmp -s test_extent.out $(srcdir)/test_extent.in ; then \
                echo "Test succeeded." ; \
        else \
index 8f6d95e76dc8632890c9b6e4aea0ac4ca13902b1..20a0c463e411c20754e2b3a9a91b87731ae41e8e 100644 (file)
@@ -1986,6 +1986,145 @@ static void quiet_com_err_proc(const char *whoami EXT2FS_ATTR((unused)),
 {
 }
 
+static int fix_ea_entries(ext2_extent imap, struct ext2_ext_attr_entry *entry,
+                         struct ext2_ext_attr_entry *end, ext2_ino_t last_ino)
+{
+       int modified = 0;
+       ext2_ino_t new_ino;
+       errcode_t retval;
+
+       while (entry < end && !EXT2_EXT_IS_LAST_ENTRY(entry)) {
+               if (entry->e_value_inum > last_ino) {
+                       new_ino = ext2fs_extent_translate(imap,
+                                                         entry->e_value_inum);
+                       entry->e_value_inum = new_ino;
+                       modified = 1;
+               }
+               entry = EXT2_EXT_ATTR_NEXT(entry);
+       }
+       return modified;
+}
+
+static int fix_ea_ibody_entries(ext2_extent imap,
+                               struct ext2_inode_large *inode, int inode_size,
+                               ext2_ino_t last_ino)
+{
+       struct ext2_ext_attr_entry *start, *end;
+       __u32 *ea_magic;
+
+       if (inode->i_extra_isize == 0)
+               return 0;
+
+       ea_magic = (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
+                               inode->i_extra_isize);
+       if (*ea_magic != EXT2_EXT_ATTR_MAGIC)
+               return 0;
+
+       start = (struct ext2_ext_attr_entry *)(ea_magic + 1);
+       end = (struct ext2_ext_attr_entry *)((char *)inode + inode_size);
+
+       return fix_ea_entries(imap, start, end, last_ino);
+}
+
+static int fix_ea_block_entries(ext2_extent imap, char *block_buf,
+                               unsigned int blocksize, ext2_ino_t last_ino)
+{
+       struct ext2_ext_attr_header *header;
+       struct ext2_ext_attr_entry *start, *end;
+
+       header = (struct ext2_ext_attr_header *)block_buf;
+       start = (struct ext2_ext_attr_entry *)(header+1);
+       end = (struct ext2_ext_attr_entry *)(block_buf + blocksize);
+
+       return fix_ea_entries(imap, start, end, last_ino);
+}
+
+/* A simple LRU cache to check recently processed blocks. */
+struct blk_cache {
+       int cursor;
+       blk64_t blks[4];
+};
+
+#define BLK_IN_CACHE(b,c) ((b) == (c).blks[0] || (b) == (c).blks[1] || \
+                          (b) == (c).blks[2] || (b) == (c).blks[3])
+#define BLK_ADD_CACHE(b,c) {                   \
+       (c).blks[(c).cursor] = (b);             \
+       (c).cursor = ((c).cursor + 1) % 4;      \
+}
+
+static errcode_t fix_ea_inode_refs(ext2_resize_t rfs, struct ext2_inode *inode,
+                                  char *block_buf, ext2_ino_t last_ino)
+{
+       ext2_filsys     fs = rfs->new_fs;
+       ext2_inode_scan scan = NULL;
+       ext2_ino_t      ino;
+       int             inode_size = EXT2_INODE_SIZE(fs->super);
+       blk64_t         blk;
+       int             modified;
+       struct blk_cache blk_cache = { 0 };
+       struct ext2_ext_attr_header *header;
+       errcode_t               retval;
+
+       header = (struct ext2_ext_attr_header *)block_buf;
+
+       retval = ext2fs_open_inode_scan(fs, 0, &scan);
+       if (retval)
+               goto out;
+
+       while (1) {
+               retval = ext2fs_get_next_inode_full(scan, &ino, inode,
+                                                   inode_size);
+               if (retval)
+                       goto out;
+               if (!ino)
+                       break;
+
+               if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
+                       continue; /* inode not in use */
+
+               if (inode_size != EXT2_GOOD_OLD_INODE_SIZE) {
+                       modified = fix_ea_ibody_entries(rfs->imap,
+                                       (struct ext2_inode_large *)inode,
+                                       inode_size, last_ino);
+                       if (modified) {
+                               retval = ext2fs_write_inode_full(fs, ino, inode,
+                                                                inode_size);
+                               if (retval)
+                                       goto out;
+                       }
+               }
+
+               blk = ext2fs_file_acl_block(fs, inode);
+               if (blk && !BLK_IN_CACHE(blk, blk_cache)) {
+                       retval = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
+                       if (retval)
+                               goto out;
+
+                       modified = fix_ea_block_entries(rfs->imap, block_buf,
+                                                       fs->blocksize,
+                                                       last_ino);
+                       if (modified) {
+                               retval = ext2fs_write_ext_attr3(fs, blk,
+                                                               block_buf, ino);
+                               if (retval)
+                                       goto out;
+                               /*
+                                * If refcount is greater than 1, we might see
+                                * the same block referenced by other inodes
+                                * later.
+                                */
+                               if (header->h_refcount > 1)
+                                       BLK_ADD_CACHE(blk, blk_cache);
+                       }
+               }
+       }
+       retval = 0;
+out:
+       if (scan)
+               ext2fs_close_inode_scan(scan);
+       return retval;
+
+}
 static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
 {
        struct process_block_struct     pb;
@@ -1996,6 +2135,7 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
        char                    *block_buf = 0;
        ext2_ino_t              start_to_move;
        int                     inode_size;
+       int                     update_ea_inode_refs = 0;
 
        if ((rfs->old_fs->group_desc_count <=
             rfs->new_fs->group_desc_count) &&
@@ -2068,7 +2208,15 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
 
                ext2fs_inode_alloc_stats2(rfs->new_fs, new_inode, +1,
                                          pb.is_dir);
-               inode->i_ctime = time(0);
+               /*
+                * i_ctime field in xattr inodes contain a portion of the ref
+                * count, do not overwrite.
+                */
+               if (inode->i_flags & EXT4_EA_INODE_FL)
+                       update_ea_inode_refs = 1;
+               else
+                       inode->i_ctime = time(0);
+
                retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
                                                inode, inode_size);
                if (retval)
@@ -2134,6 +2282,14 @@ remap_blocks:
                                goto errout;
                }
        }
+
+       if (update_ea_inode_refs &&
+           ext2fs_has_feature_ea_inode(rfs->new_fs->super)) {
+               retval = fix_ea_inode_refs(rfs, inode, block_buf,
+                                          start_to_move);
+               if (retval)
+                       goto errout;
+       }
        io_channel_flush(rfs->old_fs->io);
 
 errout:
index c130f4abe93cab7ae16dd28880c8b2c200659529..57117ac86633729610f0b2d7738cadbb2d4ea792 100644 (file)
@@ -41,8 +41,10 @@ always_run:
 @ifGNUmake@TESTS=$(wildcard $(srcdir)/[a-z]_*)
 @ifNotGNUmake@TESTS != echo $(srcdir)/[a-z]_*
 
+SKIP_SLOW_TESTS=--skip-slow-tests
+
 $(TESTS):: test_one always_run
-       @./test_one $@
+       @./test_one $(SKIP_SLOW_TESTS) $@
 
 foo:
        echo $(TESTS)
@@ -57,6 +59,9 @@ test_post: test_pre $(TESTS)
 
 check:: test_pre test_post test_script
 
+fullcheck::
+       $(MAKE) SKIP_SLOW_TESTS= check
+
 check-failed: $(basename $(wildcard *.failed))
        @$(srcdir)/test_post
 
index 8ce79ff6287b63319cc97757635c1b0b227b7aa3..f588511532bdb161875fad419feded68c89e88fd 100644 (file)
@@ -18,7 +18,7 @@ debugfs: stat /a
 Inode: 12   Type: regular    Mode:  0666   Flags: 0x0
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 40960
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 82
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
@@ -30,7 +30,7 @@ debugfs: stat /b
 Inode: 13   Type: regular    Mode:  0666   Flags: 0x0
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 10240000
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 20082
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
index b6851353c391c18af5c044fb4c55cd1b3423c71d..db9d52242a1cd2f3731670f6d28e7c963e8f3801 100644 (file)
@@ -2,7 +2,7 @@
 Inode: 13   Type: regular    Mode:  0644   Flags: 0x10000000
 Generation: 3289262644    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 80
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec6b4:c72e3c00 -- Tue Jul 22 20:16:52 2014
@@ -18,7 +18,7 @@ Size of inline data: 80
 Inode: 18   Type: regular    Mode:  0644   Flags: 0x10000000
 Generation: 3842229473    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 20
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec6b4:cafecc00 -- Tue Jul 22 20:16:52 2014
@@ -35,7 +35,7 @@ Size of inline data: 60
 Inode: 16   Type: directory    Mode:  0755   Flags: 0x10000000
 Generation: 3842229469    Version: 0x00000000:00000004
 User:     0   Group:     0   Size: 132
-File ACL: 7    Directory ACL: 0
+File ACL: 7
 Links: 2   Blockcount: 8
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec6e3:27eac000 -- Tue Jul 22 20:17:39 2014
@@ -51,7 +51,7 @@ Size of inline data: 132
 Inode: 20   Type: directory    Mode:  0755   Flags: 0x10000000
 Generation: 3710818931    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 60
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 2   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec6b4:ca0aa800 -- Tue Jul 22 20:16:52 2014
@@ -68,7 +68,7 @@ Size of inline data: 60
 Inode: 12   Type: symlink    Mode:  0777   Flags: 0x10000000
 Generation: 3289262643    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 80
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec47f:724db800 -- Tue Jul 22 20:07:27 2014
@@ -83,7 +83,7 @@ Fast link dest: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 Inode: 19   Type: symlink    Mode:  0777   Flags: 0x0
 Generation: 3842229474    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 20
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec44c:a1fcc000 -- Tue Jul 22 20:06:36 2014
index f729b0f1c7be8df44ca0e9167404e0b0a8857ef2..c825932955b9ed736eb46855ee95e3d575f12ad5 100644 (file)
@@ -5,7 +5,7 @@ debugfs -R ''stat foo'' -w test.img
 Inode: 12   Type: symlink    Mode:  0777   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 3
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
@@ -17,7 +17,7 @@ debugfs -R ''stat foo2'' -w test.img
 Inode: 13   Type: symlink    Mode:  0777   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 80
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 2
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
@@ -42,7 +42,7 @@ debugfs -R ''stat pipe'' -w test.img
 Inode: 14   Type: FIFO    Mode:  0000   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 0
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
@@ -55,7 +55,7 @@ debugfs -R ''stat sda'' -w test.img
 Inode: 15   Type: block special    Mode:  0000   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 0
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
@@ -67,7 +67,7 @@ debugfs -R ''stat null'' -w test.img
 Inode: 16   Type: character special    Mode:  0000   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 0
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
index 65a1641aed1561af970a826c21111a07d7f50aa9..b44e65d0034459414634cdc63f6ec7d7f55e75df 100644 (file)
@@ -13,8 +13,6 @@ Inode 17 logical block 0 (physical block 1186) violates cluster allocation rules
 Will fix in pass 1B.
 Inode 17 logical block 2 (physical block 1184) violates cluster allocation rules.
 Will fix in pass 1B.
-Inode 17, i_blocks is 32, should be 64.  Fix? yes
-
 Inode 18 logical block 3 (physical block 1201) violates cluster allocation rules.
 Will fix in pass 1B.
 Inode 18, i_blocks is 32, should be 64.  Fix? yes
@@ -86,8 +84,6 @@ Inode 12, i_blocks is 64, should be 32.  Fix? yes
 
 Inode 16, i_blocks is 64, should be 32.  Fix? yes
 
-Inode 17, i_blocks is 64, should be 32.  Fix? yes
-
 Inode 18, i_blocks is 64, should be 32.  Fix? yes
 
 Pass 2: Checking directory structure
@@ -116,7 +112,7 @@ debugfs: stat /a
 Inode: 12   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152157    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -128,7 +124,7 @@ debugfs: stat /b
 Inode: 13   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152158    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -140,7 +136,7 @@ debugfs: stat /c
 Inode: 14   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152159    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -152,7 +148,7 @@ debugfs: stat /d
 Inode: 15   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152160    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -163,7 +159,7 @@ debugfs: stat /e
 Inode: 16   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152161    Version: 0x00000001
 User:     0   Group:     0   Size: 6144
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -175,7 +171,7 @@ debugfs: stat /f
 Inode: 17   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152162    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -187,7 +183,7 @@ debugfs: stat /g
 Inode: 18   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152163    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
index c387962fc6c3a17a3c9cd4f4f7f2ca92e382b3c1..716dbcba75b934edf0e21bbc232d777db2f17a1c 100644 (file)
@@ -2,7 +2,7 @@ debugfs: stat /a
 Inode: 12   Type: regular    Mode:  0644   Flags: 0x0
 Generation: 1573716129    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 524288
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 1030
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x5457f87a:62ae2980 -- Mon Nov  3 21:49:46 2014
index c86c57159821b05bd11ff248dee21c4ee4f4ddb5..eafd64a4acb419a4e5d63fad4bdf30525234a377 100644 (file)
@@ -2,7 +2,7 @@ debugfs: stat /a
 Inode: 12   Type: regular    Mode:  0644   Flags: 0x0
 Generation: 1573716129    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 524288
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 1030
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x5457f87a:62ae2980 -- Mon Nov  3 21:49:46 2014
index 74a8034b1100d2a4d3163aa07b1d0e9b98129db0..095fb2b263146b8cc72064aa43c7feff50236484 100644 (file)
@@ -2,7 +2,7 @@ debugfs: stat /realmode.bin
 Inode: 12   Type: regular    Mode:  0775   Flags: 0x0
 Generation: 2022334337    Version: 0x00000001
 User:  1000   Group:  1000   Size: 21080
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 16
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x5924849d -- Tue May 23 18:51:09 2017
index dca6e92df7c03794621381d0b240943ce1f8e3d6..44093855059d52e6139564ec15d39a9f233eda06 100644 (file)
@@ -20,7 +20,7 @@ debugfs -R "stat /l_30" test.img
 Inode: 12   Type: symlink    Mode:  0777   Flags: 0x0
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 31
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
@@ -29,7 +29,7 @@ debugfs -R "stat /l_70" test.img
 Inode: 13   Type: symlink    Mode:  0777   Flags: 0x10000000
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 71
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
@@ -40,7 +40,7 @@ debugfs -R "stat /l_500" test.img
 Inode: 14   Type: symlink    Mode:  0777   Flags: 0x80000
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 501
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 2
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
@@ -50,7 +50,7 @@ debugfs -R "stat /l_1023" test.img
 Inode: 15   Type: symlink    Mode:  0777   Flags: 0x80000
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 1024
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 2
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
diff --git a/tests/f_ea_inode/expect.1 b/tests/f_ea_inode/expect.1
new file mode 100644 (file)
index 0000000..aaa0bea
--- /dev/null
@@ -0,0 +1,31 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 17 has illegal extended attribute value inode 4008636142.
+Clear? yes
+
+Inode 17, i_blocks is 8, should be 0.  Fix? yes
+
+Inode 18 has illegal extended attribute value inode 19.
+Clear? yes
+
+Inode 18, i_blocks is 8, should be 0.  Fix? yes
+
+Extended attribute in inode 20 has a hash (1145324612) which is invalid
+Clear? yes
+
+Inode 20, i_blocks is 8, should be 0.  Fix? yes
+
+EA inode 19 for parent inode 21 missing EA_INODE flag.
+ Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Extended attribute inode 16 ref count is 51, should be 2. Fix? yes
+
+Extended attribute inode 19 ref count is 2, should be 1. Fix? yes
+
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 21/32 files (0.0% non-contiguous), 18/64 blocks
+Exit status is 1
diff --git a/tests/f_ea_inode/expect.2 b/tests/f_ea_inode/expect.2
new file mode 100644 (file)
index 0000000..f9276fb
--- /dev/null
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 21/32 files (0.0% non-contiguous), 18/64 blocks
+Exit status is 0
diff --git a/tests/f_ea_inode/image.gz b/tests/f_ea_inode/image.gz
new file mode 100644 (file)
index 0000000..68a3975
Binary files /dev/null and b/tests/f_ea_inode/image.gz differ
diff --git a/tests/f_large_dir/expect b/tests/f_large_dir/expect
new file mode 100644 (file)
index 0000000..b099460
--- /dev/null
@@ -0,0 +1,12 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 3A: Optimizing directories
+Pass 4: Checking reference counts
+Inode 13 ref count is 1, should be 47245.  Fix? yes
+
+Pass 5: Checking group summary information
+
+test.img: ***** FILE SYSTEM WAS MODIFIED *****
+test.img: 13/115368 files (0.0% non-contiguous), 32817/460800 blocks
+Exit status is 1
diff --git a/tests/f_large_dir/is_slow_test b/tests/f_large_dir/is_slow_test
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/f_large_dir/name b/tests/f_large_dir/name
new file mode 100644 (file)
index 0000000..4b96890
--- /dev/null
@@ -0,0 +1 @@
+optimize 3 level htree directories
diff --git a/tests/f_large_dir/script b/tests/f_large_dir/script
new file mode 100644 (file)
index 0000000..0b5fdff
--- /dev/null
@@ -0,0 +1,51 @@
+OUT=$test_name.log
+EXP=$test_dir/expect
+E2FSCK=../e2fsck/e2fsck
+
+NAMELEN=255
+DIRENT_SZ=8
+BLOCKSZ=1024
+DIRENT_PER_LEAF=$((BLOCKSZ / (NAMELEN + DIRENT_SZ)))
+HEADER=32
+INDEX_SZ=8
+INDEX_L1=$(((BLOCKSZ - HEADER) / INDEX_SZ))
+INDEX_L2=$(((BLOCKSZ - DIRENT_SZ) / INDEX_SZ))
+ENTRIES=$((INDEX_L1 * INDEX_L2 * DIRENT_PER_LEAF))
+
+cp /dev/null $OUT
+$MKE2FS -b 1024 -O large_dir,uninit_bg,dir_nlink -F $TMPFILE 460800 \
+       > /dev/null 2>&1
+{
+       echo "feature large_dir"
+       echo "mkdir /foo"
+       echo "cd /foo"
+       touch foofile
+       echo "write foofile foofile"
+       i=0
+       while test $i  -lt $ENTRIES ; do
+           if test $(( i % DIRENT_PER_LEAF )) -eq 0 ; then
+               echo "expand ./"
+           fi
+           if test $(( i % 5000 )) -eq 0 -a $i -gt 0 ; then
+               >&2 echo "$test_name: $i processed"
+           fi
+           printf "ln foofile %0255X\n" $i
+           i=$(($i + 1))
+       done
+} | $DEBUGFS -w -f /dev/stdin $TMPFILE > /dev/null 2>&1
+
+$E2FSCK -yfD $TMPFILE > $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
+rm -f $OUT.new
+
+cmp -s $OUT $EXP
+RC=$?
+if [ $RC -eq 0 ]; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff -u $EXP $OUT > $test_name.failed
+fi
diff --git a/tests/f_mmp/is_slow_test b/tests/f_mmp/is_slow_test
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/f_mmp_garbage/is_slow_test b/tests/f_mmp_garbage/is_slow_test
new file mode 100644 (file)
index 0000000..e69de29
index 8ba81e6b2f39d7af11a63de5a7ce08705a6c298f..d4f72a1c6980ffca7d55cada8235d9e436ef0559 100644 (file)
@@ -3,7 +3,7 @@ Pass 2: Checking directory structure
 i_faddr for inode 15 (/test/quux) is 23, should be zero.
 Clear? yes
 
-i_dir_acl for inode 15 (/test/quux) is 12, should be zero.
+i_size_high for inode 15 (/test/quux) is 12, should be zero.
 Clear? yes
 
 i_file_acl for inode 13 (/test/???) is 12, should be zero.
diff --git a/tests/r_64bit_big_expand/is_slow_test b/tests/r_64bit_big_expand/is_slow_test
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/r_ext4_big_expand/is_slow_test b/tests/r_ext4_big_expand/is_slow_test
new file mode 100644 (file)
index 0000000..e69de29
index fb30e57826d48298e0744eda34f96da9b1fa3b39..35465b6a73758dbd0ffa88df7738369cb41dc74c 100644 (file)
@@ -13,6 +13,10 @@ case "$1" in
        export USE_VALGRIND="valgrind --sim-hints=lax-ioctls --leak-check=full --show-reachable=yes --log-file=/tmp/valgrind-%p.log"
        shift;
        ;;
+    --skip-slow-tests)
+       SKIP_SLOW_TESTS=yes
+       shift;
+       ;;
 esac
 
 case "$1" in
@@ -49,6 +53,11 @@ else
        test_description=
 fi
 
+if [ -n "$SKIP_SLOW_TESTS" -a -f $test_dir/is_slow_test ]; then
+    echo "$test_name: $test_description: skipped (slow test)"
+    exit 0
+fi
+
 rm -f $test_name.ok $test_name.failed
 #echo -e -n "$test_name: $test_description:\r"
 
index b3c12a7dff801c4fe5e89d01a7db283ab2db6464..e6b25fa532607baee9270bc5dbc5de6216fbeb13 100644 (file)
@@ -1,33 +1,23 @@
-/* work around bug in AndroidConfig.h */
-#ifdef HAVE_MALLOC_H
-#undef HAVE_MALLOC_H
+#ifndef __APPLE__
 #define HAVE_MALLOC_H 1
 #endif
 
 #define ROOT_SYSCONFDIR "/etc"
 
+#define ENABLE_LIBSPARSE 1
+
 #define DISABLE_BACKTRACE 1
 #define HAVE_DIRENT_H 1
 #define HAVE_ERRNO_H 1
-#define HAVE_EXT2_IOCTLS 1
-#define HAVE_FALLOCATE 1
 #define HAVE_GETOPT_H 1
-#define HAVE_GETPAGESIZE 1
 #define HAVE_GETPWUID_R 1
 #define HAVE_INTPTR_T 1
 #define HAVE_INTTYPES_H 1
-#define HAVE_LINUX_FD_H 1
-#define HAVE_LSEEK64 1
-#define HAVE_LSEEK64_PROTOTYPE 1
 #define HAVE_MMAP 1
-#define HAVE_NETINET_IN_H 1
-#define HAVE_NET_IF_H 1
-#define HAVE_POSIX_MEMALIGN 1
-#define HAVE_PREAD 1
-#define HAVE_PREAD64 1
-#define HAVE_PWRITE 1
-#define HAVE_PWRITE64 1
 #define HAVE_SETJMP_H 1
+#ifdef __linux__
+#define HAVE_SETMNTENT 1
+#endif
 #define HAVE_SNPRINTF 1
 #define HAVE_STDLIB_H 1
 #define HAVE_STRCASECMP 1
 #define HAVE_STRNLEN 1
 #define HAVE_STRPTIME 1
 #define HAVE_SYSCONF 1
-#define HAVE_SYS_IOCTL_H 1
-#define HAVE_SYS_MMAN_H 1
-#define HAVE_SYS_MOUNT_H 1
-#define HAVE_SYS_PARAM_H 1
-#define HAVE_SYS_PRCTL_H 1
-#define HAVE_SYS_RESOURCE_H 1
-#define HAVE_SYS_SELECT_H 1
-#define HAVE_SYS_STAT_H 1
-#define HAVE_SYS_TIME_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_SYS_WAIT_H 1
 #define HAVE_TYPE_SSIZE_T 1
 #define HAVE_UNISTD_H 1
 #define HAVE_UTIME_H 1
+
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+
+#if defined(_WIN32)
+# define HAVE_LINUX_TYPES_H 1
+# define HAVE_WINSOCK_H 1
+#endif
+#if defined(__APPLE__) || defined(__linux__)
+# define HAVE_FCNTL 1
+# define HAVE_FSYNC 1
+# define HAVE_GETPAGESIZE 1
+# define HAVE_NET_IF_H 1
+# define HAVE_NETINET_IN_H 1
+# define HAVE_PREAD 1
+# define HAVE_PWRITE 1
+# define HAVE_POSIX_MEMALIGN 1
+# define HAVE_SYS_IOCTL_H 1
+# define HAVE_SYS_MMAN_H 1
+# define HAVE_SYS_MOUNT_H 1
+# define HAVE_SYS_PARAM_H 1
+# define HAVE_SYS_RESOURCE_H 1
+# define HAVE_SYS_SELECT_H 1
+# define HAVE_SYS_WAIT_H 1
+#endif
+#if defined(__linux__)
+# define HAVE_EXT2_IOCTLS 1
+# define HAVE_FALLOCATE 1
+# define HAVE_LINUX_FD_H 1
+# define HAVE_LINUX_TYPES_H 1
+# define HAVE_LSEEK64 1
+# define HAVE_LSEEK64_PROTOTYPE 1
+# define HAVE_PREAD64 1
+# define HAVE_PWRITE64 1
+# define HAVE_SYS_PRCTL_H 1
+# define HAVE_SYS_SYSMACROS_H 1
+#endif
index ebd8778b7863fbfadd7b5c9887b0768425ef515c..937496bcab0d6a9b11f483a7b35634142c237bcd 100755 (executable)
@@ -7,7 +7,7 @@ ANDROID_GENERATED_FILES="lib/ext2fs/ext2_err.c lib/ext2fs/ext2_err.h \
        lib/ext2fs/ext2_types.h lib/config.h lib/blkid/blkid.h \
        lib/uuid/uuid.h lib/ext2fs/crc32c_table.h misc/default_profile.c \
        lib/ss/std_rqs.c debugfs/debug_cmds.c debugfs/ro_debug_cmds.c \
-       debugfs/extent_cmds.c debugfs/e2freefrag.c debugfs/create_inode.c \
+       debugfs/extent_cmds.c debugfs/e2freefrag.c \
        debugfs/recovery.c debugfs/revoke.c \
        MODULE_LICENSE_GPL README.version"
 
@@ -41,7 +41,7 @@ cp util/android_types.h lib/ext2fs/ext2_types.h
 cp util/android_types.h lib/blkid/blkid_types.h
 cp util/android_types.h lib/uuid/uuid_types.h
 cp util/android_config.h lib/config.h
-cp misc/e2freefrag.c misc/create_inode.c debugfs/
+cp misc/e2freefrag.c debugfs/
 cp e2fsck/recovery.c e2fsck/revoke.c debugfs/
 
 gcc -o gen_crc32ctable lib/ext2fs/gen_crc32ctable.c