am f9ad69f4: am 803b245e: (-s ours) am 469dbc0a: (-s ours) Reconcile with jb-mr1-release - do not merge
* commit 'f9ad69f467c2207e6e8ec995c2b73dde0f6a787f':
diff --git a/ext4_utils/Android.mk b/ext4_utils/Android.mk
index 99145a4..6eba3b1 100644
--- a/ext4_utils/Android.mk
+++ b/ext4_utils/Android.mk
@@ -12,7 +12,8 @@
indirect.c \
uuid.c \
sha1.c \
- wipe.c
+ wipe.c \
+ crc16.c
#
# -- All host/targets including windows
@@ -21,13 +22,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(libext4_utils_src_files)
LOCAL_MODULE := libext4_utils_host
-LOCAL_C_INCLUDES += external/zlib
-LOCAL_STATIC_LIBRARIES += libsparse_host
-ifeq ($(HAVE_SELINUX), true)
- LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_STATIC_LIBRARIES := \
+ libsparse_host \
+ libz
+ifneq ($(HOST_OS),windows)
LOCAL_STATIC_LIBRARIES += libselinux
- LOCAL_CFLAGS += -DHAVE_SELINUX
-endif # HAVE_SELINUX
+endif
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -41,11 +41,8 @@
ifeq ($(HOST_OS),windows)
LOCAL_LDLIBS += -lws2_32
else
- ifeq ($(HAVE_SELINUX), true)
- LOCAL_C_INCLUDES += external/libselinux/include
- LOCAL_STATIC_LIBRARIES += libselinux
- LOCAL_CFLAGS += -DHAVE_SELINUX
- endif # HAVE_SELINUX
+ LOCAL_STATIC_LIBRARIES += libselinux
+ LOCAL_CFLAGS := -DHOST
endif
include $(BUILD_HOST_EXECUTABLE)
@@ -59,41 +56,29 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(libext4_utils_src_files)
LOCAL_MODULE := libext4_utils
-LOCAL_C_INCLUDES += external/zlib
LOCAL_SHARED_LIBRARIES := \
+ libselinux \
libsparse \
libz
-ifeq ($(HAVE_SELINUX), true)
- LOCAL_C_INCLUDES += external/libselinux/include
- LOCAL_SHARED_LIBRARIES += libselinux
- LOCAL_CFLAGS += -DHAVE_SELINUX
-endif # HAVE_SELINUX
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(libext4_utils_src_files)
LOCAL_MODULE := libext4_utils_static
-LOCAL_C_INCLUDES += external/zlib
LOCAL_STATIC_LIBRARIES += \
+ libselinux \
libsparse_static
-ifeq ($(HAVE_SELINUX), true)
- LOCAL_C_INCLUDES += external/libselinux/include
- LOCAL_STATIC_LIBRARIES += libselinux
- LOCAL_CFLAGS += -DHAVE_SELINUX
-endif # HAVE_SELINUX
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := make_ext4fs_main.c
LOCAL_MODULE := make_ext4fs
-LOCAL_SHARED_LIBRARIES += libext4_utils libz
-ifeq ($(HAVE_SELINUX), true)
- LOCAL_C_INCLUDES += external/libselinux/include
- LOCAL_SHARED_LIBRARIES += libselinux
- LOCAL_CFLAGS += -DHAVE_SELINUX
-endif # HAVE_SELINUX
+LOCAL_SHARED_LIBRARIES := \
+ libext4_utils \
+ libselinux \
+ libz
include $(BUILD_EXECUTABLE)
@@ -102,13 +87,9 @@
LOCAL_MODULE := ext2simg
LOCAL_SHARED_LIBRARIES += \
libext4_utils \
+ libselinux \
libsparse \
libz
-ifeq ($(HAVE_SELINUX), true)
- LOCAL_C_INCLUDES += external/libselinux/include
- LOCAL_SHARED_LIBRARIES += libselinux
- LOCAL_CFLAGS += -DHAVE_SELINUX
-endif # HAVE_SELINUX
include $(BUILD_EXECUTABLE)
@@ -117,13 +98,9 @@
LOCAL_MODULE := ext2simg
LOCAL_STATIC_LIBRARIES += \
libext4_utils_host \
+ libselinux \
libsparse_host \
libz
-ifeq ($(HAVE_SELINUX), true)
- LOCAL_C_INCLUDES += external/libselinux/include
- LOCAL_STATIC_LIBRARIES += libselinux
- LOCAL_CFLAGS += -DHAVE_SELINUX
-endif # HAVE_SELINUX
include $(BUILD_HOST_EXECUTABLE)
diff --git a/ext4_utils/allocate.c b/ext4_utils/allocate.c
index adf91ba..5c60e92 100644
--- a/ext4_utils/allocate.c
+++ b/ext4_utils/allocate.c
@@ -56,9 +56,16 @@
u32 first_free_block;
u32 free_inodes;
u32 first_free_inode;
+ u16 flags;
u16 used_dirs;
};
+struct xattr_list_element {
+ struct ext4_inode *inode;
+ struct ext4_xattr_header *header;
+ struct xattr_list_element *next;
+};
+
struct block_allocation *create_allocation()
{
struct block_allocation *alloc = malloc(sizeof(struct block_allocation));
@@ -73,6 +80,25 @@
return alloc;
}
+static struct ext4_xattr_header *xattr_list_find(struct ext4_inode *inode)
+{
+ struct xattr_list_element *element;
+ for (element = aux_info.xattrs; element != NULL; element = element->next) {
+ if (element->inode == inode)
+ return element->header;
+ }
+ return NULL;
+}
+
+static void xattr_list_insert(struct ext4_inode *inode, struct ext4_xattr_header *header)
+{
+ struct xattr_list_element *element = malloc(sizeof(struct xattr_list_element));
+ element->inode = inode;
+ element->header = header;
+ element->next = aux_info.xattrs;
+ aux_info.xattrs = element;
+}
+
static void region_list_remove(struct region_list *list, struct region *reg)
{
if (reg->prev)
@@ -157,24 +183,8 @@
sparse_file_add_data(info.sparse_file, bg->inode_table,
aux_info.inode_table_blocks * info.block_size, block);
-}
-void init_unused_inode_tables(void)
-{
- unsigned int i;
- u32 block;
- struct block_group_info *bg;
-
- for (i = 0; i < aux_info.groups; i++) {
- if (!aux_info.bgs[i].inode_table) {
- bg = &aux_info.bgs[i];
- block = bg->first_block + 2;
- if (bg->has_superblock)
- block += aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks + 1;
- sparse_file_add_fill(info.sparse_file, 0,
- aux_info.inode_table_blocks * info.block_size, block);
- }
- }
+ bg->flags &= ~EXT4_BG_INODE_UNINIT;
}
static int bitmap_set_bit(u8 *bitmap, u32 bit)
@@ -297,6 +307,7 @@
bg->first_free_block = 0;
bg->free_inodes = info.inodes_per_group;
bg->first_free_inode = 1;
+ bg->flags = EXT4_BG_INODE_UNINIT;
if (reserve_blocks(bg, bg->first_free_block, bg->header_blocks) < 0)
error("failed to reserve %u blocks in block group %u\n", bg->header_blocks, i);
@@ -687,6 +698,35 @@
info.inode_size);
}
+struct ext4_xattr_header *get_xattr_block_for_inode(struct ext4_inode *inode)
+{
+ struct ext4_xattr_header *block = xattr_list_find(inode);
+ if (block != NULL)
+ return block;
+
+ u32 block_num = allocate_block();
+ block = calloc(info.block_size, 1);
+ if (block == NULL) {
+ error("get_xattr: failed to allocate %d", info.block_size);
+ return NULL;
+ }
+
+ block->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
+ block->h_refcount = cpu_to_le32(1);
+ block->h_blocks = cpu_to_le32(1);
+ inode->i_blocks_lo = cpu_to_le32(le32_to_cpu(inode->i_blocks_lo) + (info.block_size / 512));
+ inode->i_file_acl_lo = cpu_to_le32(block_num);
+
+ int result = sparse_file_add_data(info.sparse_file, block, info.block_size, block_num);
+ if (result != 0) {
+ error("get_xattr: sparse_file_add_data failure %d", result);
+ free(block);
+ return NULL;
+ }
+ xattr_list_insert(inode, block);
+ return block;
+}
+
/* Mark the first len inodes in a block group as used */
u32 reserve_inodes(int bg, u32 num)
{
@@ -744,6 +784,12 @@
return aux_info.bgs[bg].used_dirs;
}
+/* Returns the flags for a block group */
+u16 get_bg_flags(int bg)
+{
+ return aux_info.bgs[bg].flags;
+}
+
/* Frees the memory used by a linked list of allocation regions */
void free_alloc(struct block_allocation *alloc)
{
diff --git a/ext4_utils/allocate.h b/ext4_utils/allocate.h
index fb6e0f7..7a3ffed 100644
--- a/ext4_utils/allocate.h
+++ b/ext4_utils/allocate.h
@@ -21,6 +21,7 @@
#include "ext4_utils.h"
#include "ext4.h"
+#include "xattr.h"
struct block_allocation;
@@ -31,6 +32,7 @@
int block_allocation_num_regions(struct block_allocation *alloc);
int block_allocation_len(struct block_allocation *alloc);
struct ext4_inode *get_inode(u32 inode);
+struct ext4_xattr_header *get_xattr_block_for_inode(struct ext4_inode *inode);
void reduce_allocation(struct block_allocation *alloc, u32 len);
u32 get_block(struct block_allocation *alloc, u32 block);
u32 get_oob_block(struct block_allocation *alloc, u32 block);
@@ -41,6 +43,7 @@
u32 reserve_inodes(int bg, u32 inodes);
void add_directory(u32 inode);
u16 get_directories(int bg);
+u16 get_bg_flags(int bg);
void init_unused_inode_tables(void);
u32 allocate_inode();
void free_alloc(struct block_allocation *alloc);
diff --git a/ext4_utils/contents.c b/ext4_utils/contents.c
index aeed31e..3abbdc3 100644
--- a/ext4_utils/contents.c
+++ b/ext4_utils/contents.c
@@ -18,6 +18,15 @@
#include <string.h>
#include <stdio.h>
+#ifdef HAVE_ANDROID_OS
+#include <linux/capability.h>
+#else
+#include <private/android_filesystem_capability.h>
+#endif
+
+#define XATTR_SELINUX_SUFFIX "selinux"
+#define XATTR_CAPS_SUFFIX "capability"
+
#include "ext4_utils.h"
#include "ext4.h"
#include "make_ext4fs.h"
@@ -190,7 +199,7 @@
}
/* Creates a file on disk. Returns the inode number of the new file */
-u32 make_link(const char *filename, const char *link)
+u32 make_link(const char *link)
{
struct ext4_inode *inode;
u32 inode_num;
@@ -242,51 +251,231 @@
return 0;
}
-#ifdef HAVE_SELINUX
-#define XATTR_SELINUX_SUFFIX "selinux"
-
-/* XXX */
-#define cpu_to_le32(x) (x)
-#define cpu_to_le16(x) (x)
-
-int inode_set_selinux(u32 inode_num, const char *secon)
+/*
+ * Returns the amount of free space available in the specified
+ * xattr region
+ */
+static size_t xattr_free_space(struct ext4_xattr_entry *entry, char *end)
{
- struct ext4_inode *inode = get_inode(inode_num);
- u32 *hdr;
- struct ext4_xattr_entry *entry;
- size_t name_len = strlen(XATTR_SELINUX_SUFFIX);
- size_t value_len;
- size_t size, min_offs;
- char *val;
+ while(!IS_LAST_ENTRY(entry) && (((char *) entry) < end)) {
+ end -= EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
+ entry = EXT4_XATTR_NEXT(entry);
+ }
- if (!secon)
+ if (((char *) entry) > end) {
+ error("unexpected read beyond end of xattr space");
return 0;
+ }
- if (!inode)
+ return end - ((char *) entry);
+}
+
+/*
+ * Returns a pointer to the free space immediately after the
+ * last xattr element
+ */
+static struct ext4_xattr_entry* xattr_get_last(struct ext4_xattr_entry *entry)
+{
+ for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
+ // skip entry
+ }
+ return entry;
+}
+
+/*
+ * assert that the elements in the ext4 xattr section are in sorted order
+ *
+ * The ext4 filesystem requires extended attributes to be sorted when
+ * they're not stored in the inode. The kernel ext4 code uses the following
+ * sorting algorithm:
+ *
+ * 1) First sort extended attributes by their name_index. For example,
+ * EXT4_XATTR_INDEX_USER (1) comes before EXT4_XATTR_INDEX_SECURITY (6).
+ * 2) If the name_indexes are equal, then sorting is based on the length
+ * of the name. For example, XATTR_SELINUX_SUFFIX ("selinux") comes before
+ * XATTR_CAPS_SUFFIX ("capability") because "selinux" is shorter than "capability"
+ * 3) If the name_index and name_length are equal, then memcmp() is used to determine
+ * which name comes first. For example, "selinux" would come before "yelinux".
+ *
+ * This method is intended to implement the sorting function defined in
+ * the Linux kernel file fs/ext4/xattr.c function ext4_xattr_find_entry().
+ */
+static void xattr_assert_sane(struct ext4_xattr_entry *entry)
+{
+ for( ; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
+ struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry);
+ if (IS_LAST_ENTRY(next)) {
+ return;
+ }
+
+ int cmp = next->e_name_index - entry->e_name_index;
+ if (cmp == 0)
+ cmp = next->e_name_len - entry->e_name_len;
+ if (cmp == 0)
+ cmp = memcmp(next->e_name, entry->e_name, next->e_name_len);
+ if (cmp < 0) {
+ error("BUG: extended attributes are not sorted\n");
+ return;
+ }
+ if (cmp == 0) {
+ error("BUG: duplicate extended attributes detected\n");
+ return;
+ }
+ }
+}
+
+#define NAME_HASH_SHIFT 5
+#define VALUE_HASH_SHIFT 16
+
+static void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
+ struct ext4_xattr_entry *entry)
+{
+ __u32 hash = 0;
+ char *name = entry->e_name;
+ int n;
+
+ for (n = 0; n < entry->e_name_len; n++) {
+ hash = (hash << NAME_HASH_SHIFT) ^
+ (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
+ *name++;
+ }
+
+ if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+ __le32 *value = (__le32 *)((char *)header +
+ le16_to_cpu(entry->e_value_offs));
+ for (n = (le32_to_cpu(entry->e_value_size) +
+ EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) {
+ hash = (hash << VALUE_HASH_SHIFT) ^
+ (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
+ le32_to_cpu(*value++);
+ }
+ }
+ entry->e_hash = cpu_to_le32(hash);
+}
+
+#undef NAME_HASH_SHIFT
+#undef VALUE_HASH_SHIFT
+
+static struct ext4_xattr_entry* xattr_addto_range(
+ void *block_start,
+ void *block_end,
+ struct ext4_xattr_entry *first,
+ int name_index,
+ const char *name,
+ const void *value,
+ size_t value_len)
+{
+ size_t name_len = strlen(name);
+ if (name_len > 255)
+ return NULL;
+
+ size_t available_size = xattr_free_space(first, block_end);
+ size_t needed_size = EXT4_XATTR_LEN(name_len) + EXT4_XATTR_SIZE(value_len);
+
+ if (needed_size > available_size)
+ return NULL;
+
+ struct ext4_xattr_entry *new_entry = xattr_get_last(first);
+ memset(new_entry, 0, EXT4_XATTR_LEN(name_len));
+
+ new_entry->e_name_len = name_len;
+ new_entry->e_name_index = name_index;
+ memcpy(new_entry->e_name, name, name_len);
+ new_entry->e_value_block = 0;
+ new_entry->e_value_size = cpu_to_le32(value_len);
+
+ char *val = (char *) new_entry + available_size - EXT4_XATTR_SIZE(value_len);
+ size_t e_value_offs = val - (char *) block_start;
+
+ new_entry->e_value_offs = cpu_to_le16(e_value_offs);
+ memset(val, 0, EXT4_XATTR_SIZE(value_len));
+ memcpy(val, value, value_len);
+
+ xattr_assert_sane(first);
+ return new_entry;
+}
+
+static int xattr_addto_inode(struct ext4_inode *inode, int name_index,
+ const char *name, const void *value, size_t value_len)
+{
+ struct ext4_xattr_ibody_header *hdr = (struct ext4_xattr_ibody_header *) (inode + 1);
+ struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (hdr + 1);
+ char *block_end = ((char *) inode) + info.inode_size;
+
+ struct ext4_xattr_entry *result =
+ xattr_addto_range(first, block_end, first, name_index, name, value, value_len);
+
+ if (result == NULL)
return -1;
- hdr = (u32 *) (inode + 1);
- *hdr = cpu_to_le32(EXT4_XATTR_MAGIC);
- entry = (struct ext4_xattr_entry *) (hdr+1);
- memset(entry, 0, EXT4_XATTR_LEN(name_len));
- entry->e_name_index = EXT4_XATTR_INDEX_SECURITY;
- entry->e_name_len = name_len;
- memcpy(entry->e_name, XATTR_SELINUX_SUFFIX, name_len);
- value_len = strlen(secon)+1;
- entry->e_value_size = cpu_to_le32(value_len);
- min_offs = (char *)inode + info.inode_size - (char*) entry;
- size = EXT4_XATTR_SIZE(value_len);
- val = (char *)entry + min_offs - size;
- entry->e_value_offs = cpu_to_le16(min_offs - size);
- memset(val + size - EXT4_XATTR_PAD, 0, EXT4_XATTR_PAD);
- memcpy(val, secon, value_len);
+ hdr->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
inode->i_extra_isize = cpu_to_le16(sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE);
return 0;
}
-#else
-int inode_set_selinux(u32 inode_num, const char *secon)
+
+static int xattr_addto_block(struct ext4_inode *inode, int name_index,
+ const char *name, const void *value, size_t value_len)
{
+ struct ext4_xattr_header *header = get_xattr_block_for_inode(inode);
+ if (!header)
+ return -1;
+
+ struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (header + 1);
+ char *block_end = ((char *) header) + info.block_size;
+
+ struct ext4_xattr_entry *result =
+ xattr_addto_range(header, block_end, first, name_index, name, value, value_len);
+
+ if (result == NULL)
+ return -1;
+
+ ext4_xattr_hash_entry(header, result);
return 0;
}
-#endif
+
+
+static int xattr_add(u32 inode_num, int name_index, const char *name,
+ const void *value, size_t value_len)
+{
+ if (!value)
+ return 0;
+
+ struct ext4_inode *inode = get_inode(inode_num);
+
+ if (!inode)
+ return -1;
+
+ int result = xattr_addto_inode(inode, name_index, name, value, value_len);
+ if (result != 0) {
+ result = xattr_addto_block(inode, name_index, name, value, value_len);
+ }
+ return result;
+}
+
+int inode_set_selinux(u32 inode_num, const char *secon)
+{
+ if (!secon)
+ return 0;
+
+ return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY,
+ XATTR_SELINUX_SUFFIX, secon, strlen(secon) + 1);
+}
+
+int inode_set_capabilities(u32 inode_num, uint64_t capabilities) {
+ if (capabilities == 0)
+ return 0;
+
+ struct vfs_cap_data cap_data;
+ 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[0].inheritable = 0;
+ cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
+ cap_data.data[1].inheritable = 0;
+
+ return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY,
+ XATTR_CAPS_SUFFIX, &cap_data, sizeof(cap_data));
+}
+
diff --git a/ext4_utils/contents.h b/ext4_utils/contents.h
index 35867fd..4272000 100644
--- a/ext4_utils/contents.h
+++ b/ext4_utils/contents.h
@@ -30,12 +30,14 @@
u32 *inode;
u32 mtime;
char *secon;
+ uint64_t capabilities;
};
u32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries,
u32 dirs);
u32 make_file(const char *filename, u64 len);
-u32 make_link(const char *filename, const char *link);
+u32 make_link(const char *link);
int inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime);
int inode_set_selinux(u32 inode_num, const char *secon);
+int inode_set_capabilities(u32 inode_num, uint64_t capabilities);
#endif
diff --git a/ext4_utils/crc16.c b/ext4_utils/crc16.c
new file mode 100644
index 0000000..2575812
--- /dev/null
+++ b/ext4_utils/crc16.c
@@ -0,0 +1,58 @@
+/*-
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+
+/* CRC32 code derived from work by Gary S. Brown. */
+
+/* Code taken from FreeBSD 8 */
+
+/* Converted to crc16 */
+
+#include "ext4_utils.h"
+
+static u16 crc16_tab[] = {
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
+};
+
+u16 ext4_crc16(u16 crc_in, const void *buf, int size)
+{
+ const u8 *p = buf;
+ u16 crc = crc_in;
+
+ while (size--)
+ crc = crc16_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+ return crc;
+}
diff --git a/ext4_utils/ext2simg.c b/ext4_utils/ext2simg.c
index f4b6c93..7b63836 100644
--- a/ext4_utils/ext2simg.c
+++ b/ext4_utils/ext2simg.c
@@ -57,7 +57,6 @@
{
off64_t ret;
struct ext4_super_block sb;
- unsigned int i;
ret = lseek64(fd, 1024, SEEK_SET);
if (ret < 0)
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c
index 43b4480..c3bec96 100644
--- a/ext4_utils/ext4_utils.c
+++ b/ext4_utils/ext4_utils.c
@@ -25,6 +25,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <stddef.h>
#include <string.h>
#ifdef USE_MINGW
@@ -125,6 +126,7 @@
aux_info.bg_desc = calloc(info.block_size, aux_info.bg_desc_blocks);
if (!aux_info.bg_desc)
critical_error_errno("calloc");
+ aux_info.xattrs = NULL;
}
void ext4_free_fs_aux_info()
@@ -362,11 +364,12 @@
block group */
void ext4_update_free()
{
- unsigned int i;
+ u32 i;
for (i = 0; i < aux_info.groups; i++) {
u32 bg_free_blocks = get_free_blocks(i);
u32 bg_free_inodes = get_free_inodes(i);
+ u16 crc;
aux_info.bg_desc[i].bg_free_blocks_count = bg_free_blocks;
aux_info.sb->s_free_blocks_count_lo += bg_free_blocks;
@@ -375,6 +378,13 @@
aux_info.sb->s_free_inodes_count += bg_free_inodes;
aux_info.bg_desc[i].bg_used_dirs_count += get_directories(i);
+
+ aux_info.bg_desc[i].bg_flags = get_bg_flags(i);
+
+ crc = ext4_crc16(~0, aux_info.sb->s_uuid, sizeof(aux_info.sb->s_uuid));
+ crc = ext4_crc16(crc, &i, sizeof(i));
+ crc = ext4_crc16(crc, &aux_info.bg_desc[i], offsetof(struct ext2_group_desc, bg_checksum));
+ aux_info.bg_desc[i].bg_checksum = crc;
}
}
diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h
index cad2eae..0a9bd56 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -36,6 +36,7 @@
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
+#include <stdint.h>
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
@@ -84,6 +85,12 @@
#define __u16 u16
#define __u8 u8
+/* XXX */
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
+
typedef unsigned long long u64;
typedef signed long long s64;
typedef unsigned int u32;
@@ -91,6 +98,7 @@
typedef unsigned char u8;
struct block_group_info;
+struct xattr_list_element;
struct ext2_group_desc {
__le32 bg_block_bitmap;
@@ -99,8 +107,10 @@
__le16 bg_free_blocks_count;
__le16 bg_free_inodes_count;
__le16 bg_used_dirs_count;
- __le16 bg_pad;
- __le32 bg_reserved[3];
+ __le16 bg_flags;
+ __le32 bg_reserved[2];
+ __le16 bg_reserved16;
+ __le16 bg_checksum;
};
struct fs_info {
@@ -128,6 +138,7 @@
struct ext4_super_block **backup_sb;
struct ext2_group_desc *bg_desc;
struct block_group_info *bgs;
+ struct xattr_list_element *xattrs;
u32 first_data_block;
u64 len_blocks;
u32 inode_table_blocks;
@@ -166,6 +177,17 @@
u64 get_file_size(int fd);
u64 parse_num(const char *arg);
void ext4_parse_sb(struct ext4_super_block *sb);
+u16 ext4_crc16(u16 crc_in, const void *buf, int size);
+
+typedef void (*fs_config_func_t)(const char *path, int dir, unsigned *uid, unsigned *gid,
+ unsigned *mode, uint64_t *capabilities);
+
+struct selabel_handle;
+
+int make_ext4fs_internal(int fd, const char *directory,
+ const char *mountpoint, fs_config_func_t fs_config_func, int gzip,
+ int sparse, int crc, int wipe,
+ struct selabel_handle *sehnd, int verbose);
#ifdef __cplusplus
}
diff --git a/ext4_utils/ext4fixup.c b/ext4_utils/ext4fixup.c
index f0124f8..d271116 100644
--- a/ext4_utils/ext4fixup.c
+++ b/ext4_utils/ext4fixup.c
@@ -200,7 +200,6 @@
{
off64_t ret;
struct ext4_super_block sb;
- unsigned int i;
read_sb(fd, &sb);
@@ -510,7 +509,7 @@
return count;
}
-static int get_extent_ents(int fd, struct ext4_extent_header *ext_hdr, unsigned long long *block_list)
+static int get_extent_ents(struct ext4_extent_header *ext_hdr, unsigned long long *block_list)
{
int i, j;
struct ext4_extent *extent;
@@ -560,7 +559,7 @@
tmp_ext_hdr = (struct ext4_extent_header *)block;
if (tmp_ext_hdr->eh_depth == 0) {
- get_extent_ents(fd, tmp_ext_hdr, block_list); /* leaf node, fill in block_list */
+ get_extent_ents(tmp_ext_hdr, block_list); /* leaf node, fill in block_list */
} else {
get_extent_idx(fd, tmp_ext_hdr, block_list); /* recurse down the tree */
}
@@ -581,7 +580,7 @@
}
if (extent_hdr->eh_depth == 0) {
- get_extent_ents(fd, (struct ext4_extent_header *)inode->i_block, block_list);
+ get_extent_ents((struct ext4_extent_header *)inode->i_block, block_list);
return 0;
}
diff --git a/ext4_utils/indirect.c b/ext4_utils/indirect.c
index 3d97ec8..cd826ac 100644
--- a/ext4_utils/indirect.c
+++ b/ext4_utils/indirect.c
@@ -387,7 +387,7 @@
}
static struct block_allocation *do_inode_allocate_indirect(
- struct ext4_inode *inode, u32 block_len)
+ u32 block_len)
{
u32 indirect_len = indirect_blocks_needed(block_len);
@@ -408,7 +408,7 @@
u32 block_len = DIV_ROUND_UP(len, info.block_size);
u32 indirect_len = indirect_blocks_needed(block_len);
- alloc = do_inode_allocate_indirect(inode, block_len);
+ alloc = do_inode_allocate_indirect(block_len);
if (alloc == NULL) {
error("failed to allocate extents for %lu bytes", len);
return;
@@ -494,7 +494,7 @@
u32 block_len = DIV_ROUND_UP(len, info.block_size);
u8 *data = NULL;
- alloc = do_inode_allocate_indirect(inode, block_len);
+ alloc = do_inode_allocate_indirect(block_len);
if (alloc == NULL) {
error("failed to allocate extents for %lu bytes", len);
return NULL;
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index db6fbe6..c2a2665 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -59,6 +59,10 @@
#else
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/android.h>
+
#define O_BINARY 0
#endif
@@ -97,10 +101,15 @@
#ifndef USE_MINGW
/* Read a local directory and create the same tree in the generated filesystem.
- Calls itself recursively with each directory in the given directory */
+ Calls itself recursively with each directory in the given directory.
+ full_path is an absolute or relative path, with a trailing slash, to the
+ directory on disk that should be copied, or NULL if this is a directory
+ that does not exist on disk (e.g. lost+found).
+ dir_path is an absolute path, with trailing slash, to the same directory
+ if the image were mounted at the specified mount point */
static u32 build_directory_structure(const char *full_path, const char *dir_path,
u32 dir_inode, fs_config_func_t fs_config_func,
- struct selabel_handle *sehnd)
+ struct selabel_handle *sehnd, int verbose)
{
int entries = 0;
struct dentry *dentries;
@@ -139,8 +148,8 @@
if (dentries[i].filename == NULL)
critical_error_errno("strdup");
- asprintf(&dentries[i].path, "%s/%s", dir_path, namelist[i]->d_name);
- asprintf(&dentries[i].full_path, "%s/%s", full_path, namelist[i]->d_name);
+ asprintf(&dentries[i].path, "%s%s", dir_path, namelist[i]->d_name);
+ asprintf(&dentries[i].full_path, "%s%s", full_path, namelist[i]->d_name);
free(namelist[i]);
@@ -155,30 +164,30 @@
dentries[i].size = stat.st_size;
dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
dentries[i].mtime = stat.st_mtime;
+ uint64_t capabilities;
if (fs_config_func != NULL) {
#ifdef ANDROID
unsigned int mode = 0;
unsigned int uid = 0;
unsigned int gid = 0;
int dir = S_ISDIR(stat.st_mode);
- fs_config_func(dentries[i].path, dir, &uid, &gid, &mode);
+ fs_config_func(dentries[i].path, dir, &uid, &gid, &mode, &capabilities);
dentries[i].mode = mode;
dentries[i].uid = uid;
dentries[i].gid = gid;
+ dentries[i].capabilities = capabilities;
#else
error("can't set android permissions - built without android support");
#endif
}
-#ifdef HAVE_SELINUX
+#ifndef USE_MINGW
if (sehnd) {
- char *sepath = NULL;
- asprintf(&sepath, "/%s", dentries[i].path);
- if (selabel_lookup(sehnd, &dentries[i].secon, sepath, stat.st_mode) < 0) {
- error("cannot lookup security context for %s", sepath);
+ if (selabel_lookup(sehnd, &dentries[i].secon, dentries[i].path, stat.st_mode) < 0) {
+ error("cannot lookup security context for %s", dentries[i].path);
}
- if (dentries[i].secon)
- printf("Labeling %s as %s\n", sepath, dentries[i].secon);
- free(sepath);
+
+ if (dentries[i].secon && verbose)
+ printf("Labeling %s as %s\n", dentries[i].path, dentries[i].secon);
}
#endif
@@ -215,22 +224,17 @@
dentries = tmp;
dentries[0].filename = strdup("lost+found");
- asprintf(&dentries[0].path, "%s/lost+found", dir_path);
+ asprintf(&dentries[0].path, "%slost+found", dir_path);
dentries[0].full_path = NULL;
dentries[0].size = 0;
dentries[0].mode = S_IRWXU;
dentries[0].file_type = EXT4_FT_DIR;
dentries[0].uid = 0;
dentries[0].gid = 0;
-#ifdef HAVE_SELINUX
if (sehnd) {
- char *sepath = NULL;
- asprintf(&sepath, "/%s", dentries[0].path);
- if (selabel_lookup(sehnd, &dentries[0].secon, sepath, dentries[0].mode) < 0)
+ if (selabel_lookup(sehnd, &dentries[0].secon, dentries[0].path, dentries[0].mode) < 0)
error("cannot lookup security context for %s", dentries[0].path);
- free(sepath);
}
-#endif
entries++;
dirs++;
}
@@ -241,10 +245,22 @@
if (dentries[i].file_type == EXT4_FT_REG_FILE) {
entry_inode = make_file(dentries[i].full_path, dentries[i].size);
} else if (dentries[i].file_type == EXT4_FT_DIR) {
- entry_inode = build_directory_structure(dentries[i].full_path,
- dentries[i].path, inode, fs_config_func, sehnd);
+ char *subdir_full_path = NULL;
+ char *subdir_dir_path;
+ if (dentries[i].full_path) {
+ ret = asprintf(&subdir_full_path, "%s/", dentries[i].full_path);
+ if (ret < 0)
+ critical_error_errno("asprintf");
+ }
+ ret = asprintf(&subdir_dir_path, "%s/", dentries[i].path);
+ if (ret < 0)
+ critical_error_errno("asprintf");
+ entry_inode = build_directory_structure(subdir_full_path,
+ subdir_dir_path, inode, fs_config_func, sehnd, verbose);
+ free(subdir_full_path);
+ free(subdir_dir_path);
} else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
- entry_inode = make_link(dentries[i].full_path, dentries[i].link);
+ entry_inode = make_link(dentries[i].link);
} else {
error("unknown file type on %s", dentries[i].path);
entry_inode = 0;
@@ -256,9 +272,20 @@
dentries[i].mtime);
if (ret)
error("failed to set permissions on %s\n", dentries[i].path);
+
+ /*
+ * It's important to call inode_set_selinux() before
+ * inode_set_capabilities(). Extended attributes need to
+ * be stored sorted order, and we guarantee this by making
+ * the calls in the proper order.
+ * Please see xattr_assert_sane() in contents.c
+ */
ret = inode_set_selinux(entry_inode, dentries[i].secon);
if (ret)
error("failed to set SELinux context on %s\n", dentries[i].path);
+ ret = inode_set_capabilities(entry_inode, dentries[i].capabilities);
+ if (ret)
+ error("failed to set capability on %s\n", dentries[i].path);
free(dentries[i].path);
free(dentries[i].full_path);
@@ -341,7 +368,16 @@
}
}
-int make_ext4fs(const char *filename, s64 len,
+int make_ext4fs_sparse_fd(int fd, long long len,
+ const char *mountpoint, struct selabel_handle *sehnd)
+{
+ reset_ext4fs_info();
+ info.len = len;
+
+ return make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 1, 0, 0, sehnd, 0);
+}
+
+int make_ext4fs(const char *filename, long long len,
const char *mountpoint, struct selabel_handle *sehnd)
{
int fd;
@@ -356,22 +392,92 @@
return EXIT_FAILURE;
}
- status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, 0, sehnd);
+ status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, sehnd, 0);
close(fd);
return status;
}
-int make_ext4fs_internal(int fd, const char *directory,
- char *mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse,
- int crc, int wipe, int init_itabs, struct selabel_handle *sehnd)
+/* return a newly-malloc'd string that is a copy of str. The new string
+ is guaranteed to have a trailing slash. If absolute is true, the new string
+ is also guaranteed to have a leading slash.
+*/
+static char *canonicalize_slashes(const char *str, bool absolute)
+{
+ char *ret;
+ int len = strlen(str);
+ int newlen = len;
+ char *ptr;
+
+ if (len == 0 && absolute) {
+ return strdup("/");
+ }
+
+ if (str[0] != '/' && absolute) {
+ newlen++;
+ }
+ if (str[len - 1] != '/') {
+ newlen++;
+ }
+ ret = malloc(newlen + 1);
+ if (!ret) {
+ critical_error("malloc");
+ }
+
+ ptr = ret;
+ if (str[0] != '/' && absolute) {
+ *ptr++ = '/';
+ }
+
+ strcpy(ptr, str);
+ ptr += len;
+
+ if (str[len - 1] != '/') {
+ *ptr++ = '/';
+ }
+
+ if (ptr != ret + newlen) {
+ critical_error("assertion failed\n");
+ }
+
+ *ptr = '\0';
+
+ return ret;
+}
+
+static char *canonicalize_abs_slashes(const char *str)
+{
+ return canonicalize_slashes(str, true);
+}
+
+static char *canonicalize_rel_slashes(const char *str)
+{
+ return canonicalize_slashes(str, false);
+}
+
+int make_ext4fs_internal(int fd, const char *_directory,
+ const char *_mountpoint, fs_config_func_t fs_config_func, int gzip,
+ int sparse, int crc, int wipe,
+ struct selabel_handle *sehnd, int verbose)
{
u32 root_inode_num;
u16 root_mode;
+ char *mountpoint;
+ char *directory = NULL;
if (setjmp(setjmp_env))
return EXIT_FAILURE; /* Handle a call to longjmp() */
+ if (_mountpoint == NULL) {
+ mountpoint = strdup("");
+ } else {
+ mountpoint = canonicalize_abs_slashes(_mountpoint);
+ }
+
+ if (_directory) {
+ directory = canonicalize_rel_slashes(_directory);
+ }
+
if (info.len <= 0)
info.len = get_file_size(fd);
@@ -409,11 +515,13 @@
info.inodes_per_group = compute_inodes_per_group();
info.feat_compat |=
- EXT4_FEATURE_COMPAT_RESIZE_INODE;
+ EXT4_FEATURE_COMPAT_RESIZE_INODE |
+ EXT4_FEATURE_COMPAT_EXT_ATTR;
info.feat_ro_compat |=
EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER |
- EXT4_FEATURE_RO_COMPAT_LARGE_FILE;
+ EXT4_FEATURE_RO_COMPAT_LARGE_FILE |
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
info.feat_incompat |=
EXT4_FEATURE_INCOMPAT_EXTENTS |
@@ -459,7 +567,7 @@
#else
if (directory)
root_inode_num = build_directory_structure(directory, mountpoint, 0,
- fs_config_func, sehnd);
+ fs_config_func, sehnd, verbose);
else
root_inode_num = build_default_directory_structure();
#endif
@@ -467,34 +575,25 @@
root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
-#ifdef HAVE_SELINUX
+#ifndef USE_MINGW
if (sehnd) {
- char *sepath = NULL;
char *secontext = NULL;
- if (mountpoint[0] == '/')
- sepath = strdup(mountpoint);
- else
- asprintf(&sepath, "/%s", mountpoint);
- if (!sepath)
- critical_error_errno("malloc");
- if (selabel_lookup(sehnd, &secontext, sepath, S_IFDIR) < 0) {
- error("cannot lookup security context for %s", sepath);
+ if (selabel_lookup(sehnd, &secontext, mountpoint, S_IFDIR) < 0) {
+ error("cannot lookup security context for %s", mountpoint);
}
if (secontext) {
- printf("Labeling %s as %s\n", sepath, secontext);
+ if (verbose) {
+ printf("Labeling %s as %s\n", mountpoint, secontext);
+ }
inode_set_selinux(root_inode_num, secontext);
}
- free(sepath);
freecon(secontext);
}
#endif
ext4_update_free();
- if (init_itabs)
- init_unused_inode_tables();
-
ext4_queue_sb();
printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
@@ -511,5 +610,8 @@
sparse_file_destroy(info.sparse_file);
info.sparse_file = NULL;
+ free(mountpoint);
+ free(directory);
+
return 0;
}
diff --git a/ext4_utils/make_ext4fs.h b/ext4_utils/make_ext4fs.h
index c217c3d..3784a9e 100644
--- a/ext4_utils/make_ext4fs.h
+++ b/ext4_utils/make_ext4fs.h
@@ -17,29 +17,16 @@
#ifndef _MAKE_EXT4FS_H_
#define _MAKE_EXT4FS_H_
-#include "ext4_utils.h"
-#include "ext4.h"
-
#ifdef __cplusplus
extern "C" {
#endif
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-#else
struct selabel_handle;
-#endif
-typedef void (*fs_config_func_t)(const char *path, int dir, unsigned *uid, unsigned *gid,
- unsigned *mode);
-
-void reset_ext4fs_info();
-int make_ext4fs(const char *filename, s64 len,
+int make_ext4fs(const char *filename, long long len,
const char *mountpoint, struct selabel_handle *sehnd);
-int make_ext4fs_internal(int fd, const char *directory,
- char *mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse,
- int crc, int wipe, int init_itabs, struct selabel_handle *sehnd);
+int make_ext4fs_sparse_fd(int fd, long long len,
+ const char *mountpoint, struct selabel_handle *sehnd);
#ifdef __cplusplus
}
diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c
index f7beeb5..b6c740d 100644
--- a/ext4_utils/make_ext4fs_main.c
+++ b/ext4_utils/make_ext4fs_main.c
@@ -16,6 +16,7 @@
#include <fcntl.h>
#include <libgen.h>
+#include <stdio.h>
#include <unistd.h>
#if defined(__linux__)
@@ -28,7 +29,16 @@
#include <private/android_filesystem_config.h>
#endif
+#ifndef USE_MINGW
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/android.h>
+#else
+struct selabel_handle;
+#endif
+
#include "make_ext4fs.h"
+#include "ext4_utils.h"
#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
#define O_BINARY 0
@@ -43,7 +53,7 @@
fprintf(stderr, " [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n");
fprintf(stderr, " [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n");
fprintf(stderr, " [ -S file_contexts ]\n");
- fprintf(stderr, " [ -z | -s ] [ -t ] [ -w ] [ -c ] [ -J ]\n");
+ fprintf(stderr, " [ -z | -s ] [ -w ] [ -c ] [ -J ] [ -v ]\n");
fprintf(stderr, " <filename> [<directory>]\n");
}
@@ -52,21 +62,21 @@
int opt;
const char *filename = NULL;
const char *directory = NULL;
- char *mountpoint = "";
+ char *mountpoint = NULL;
fs_config_func_t fs_config_func = NULL;
int gzip = 0;
int sparse = 0;
int crc = 0;
int wipe = 0;
- int init_itabs = 0;
int fd;
int exitcode;
+ int verbose = 0;
struct selabel_handle *sehnd = NULL;
-#ifdef HAVE_SELINUX
+#ifndef USE_MINGW
struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
#endif
- while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsctS:")) != -1) {
+ while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:fwzJsctv")) != -1) {
switch (opt) {
case 'l':
info.len = parse_num(optarg);
@@ -118,10 +128,10 @@
sparse = 1;
break;
case 't':
- init_itabs = 1;
+ fprintf(stderr, "Warning: -t (initialize inode tables) is deprecated\n");
break;
case 'S':
-#ifdef HAVE_SELINUX
+#ifndef USE_MINGW
seopts[0].value = optarg;
sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
if (!sehnd) {
@@ -129,13 +139,28 @@
exit(EXIT_FAILURE);
}
#endif
- break;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
default: /* '?' */
usage(argv[0]);
exit(EXIT_FAILURE);
}
}
+#if !defined(HOST)
+ // Use only if -S option not requested
+ if (!sehnd && mountpoint) {
+ sehnd = selinux_android_file_context_handle();
+
+ if (!sehnd) {
+ perror(optarg);
+ exit(EXIT_FAILURE);
+ }
+ }
+#endif
+
if (wipe && sparse) {
fprintf(stderr, "Cannot specifiy both wipe and sparse\n");
usage(argv[0]);
@@ -168,7 +193,7 @@
if (strcmp(filename, "-")) {
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
if (fd < 0) {
- error_errno("open");
+ perror("open");
return EXIT_FAILURE;
}
} else {
@@ -176,7 +201,7 @@
}
exitcode = make_ext4fs_internal(fd, directory, mountpoint, fs_config_func, gzip,
- sparse, crc, wipe, init_itabs, sehnd);
+ sparse, crc, wipe, sehnd, verbose);
close(fd);
return exitcode;
diff --git a/ext4_utils/mkuserimg.sh b/ext4_utils/mkuserimg.sh
index 1136a9e..c44129e 100755
--- a/ext4_utils/mkuserimg.sh
+++ b/ext4_utils/mkuserimg.sh
@@ -17,7 +17,7 @@
shift
fi
-if [ $# -ne 4 -a $# -ne 5 -a $# -ne 6 ]; then
+if [ $# -ne 5 -a $# -ne 6 ]; then
usage
exit 1
fi
@@ -45,7 +45,8 @@
fi
if [ -z $SIZE ]; then
- SIZE=128M
+ echo "Need size of filesystem"
+ exit 2
fi
if [ -n "$FC" ]; then
diff --git a/ext4_utils/xattr.h b/ext4_utils/xattr.h
index 2c6d9cc..60c01ce 100644
--- a/ext4_utils/xattr.h
+++ b/ext4_utils/xattr.h
@@ -1,8 +1,24 @@
#include <sys/types.h>
+#ifndef _SYSTEM_EXTRAS_EXT4_UTILS_XATTR_H
+#define _SYSTEM_EXTRAS_EXT4_UTILS_XATTR_H 1
+
#define EXT4_XATTR_MAGIC 0xEA020000
#define EXT4_XATTR_INDEX_SECURITY 6
+struct ext4_xattr_header {
+ __le32 h_magic;
+ __le32 h_refcount;
+ __le32 h_blocks;
+ __le32 h_hash;
+ __le32 h_checksum;
+ __u32 h_reserved[3];
+};
+
+struct ext4_xattr_ibody_header {
+ __le32 h_magic;
+};
+
struct ext4_xattr_entry {
__u8 e_name_len;
__u8 e_name_index;
@@ -19,5 +35,11 @@
#define EXT4_XATTR_LEN(name_len) \
(((name_len) + EXT4_XATTR_ROUND + \
sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
+#define EXT4_XATTR_NEXT(entry) \
+ ((struct ext4_xattr_entry *)( \
+ (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)))
#define EXT4_XATTR_SIZE(size) \
(((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
+#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
+
+#endif /* !_SYSTEM_EXTRAS_EXT4_UTILS_XATTR_H */
diff --git a/micro_bench/Android.mk b/micro_bench/Android.mk
index 0e819c3..09913ff 100644
--- a/micro_bench/Android.mk
+++ b/micro_bench/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := micro_bench.c
+LOCAL_SRC_FILES := micro_bench.cpp
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := debug
diff --git a/micro_bench/micro_bench.c b/micro_bench/micro_bench.c
deleted file mode 100644
index df6e169..0000000
--- a/micro_bench/micro_bench.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
-** Copyright 2010 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.
-*/
-
-/*
- * Some quick and dirty micro-benchmarks
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <stdint.h>
-#include <string.h>
-
-/* tv2 -= tv1 */
-static void tv_sub(struct timeval *tv2, struct timeval *tv1) {
- tv2->tv_sec -= tv1->tv_sec;
- tv2->tv_usec -= tv1->tv_usec;
- while (tv2->tv_usec < 0) {
- tv2->tv_usec += 1000000;
- tv2->tv_sec -= 1;
- }
-}
-
-static int do_sleep(int iters, int delay) {
- struct timeval tv1;
- struct timeval tv2;
- int i;
-
- for (i = 0; iters == -1 || i < iters; i++) {
- gettimeofday(&tv1, NULL);
- sleep(delay);
- gettimeofday(&tv2, NULL);
-
- tv_sub(&tv2, &tv1);
-
- printf("sleep(%d) took %ld.%06ld seconds\n", delay, tv2.tv_sec, tv2.tv_usec);
- }
-
- return 0;
-}
-
-int cpu_foo;
-
-static int do_cpu(int iters, int a) {
- struct timeval tv1;
- struct timeval tv2;
- int i;
-
- for (i = 0; iters == -1 || i < iters; i++) {
- gettimeofday(&tv1, NULL);
- for (cpu_foo = 0; cpu_foo < 100000000; cpu_foo++);
- gettimeofday(&tv2, NULL);
-
- tv_sub(&tv2, &tv1);
-
- printf("cpu took %ld.%06ld seconds\n", tv2.tv_sec, tv2.tv_usec);
- }
- return 0;
-}
-
-static double mb_sec(unsigned long bytes, struct timeval *delta) {
- unsigned long us = delta->tv_sec * 1000000 + delta->tv_usec;
- return (double)bytes * 1000000.0 / 1048576.0 / (double)us;
-}
-
-static int do_memset(int iters, int sz) {
- struct timeval tv1;
- struct timeval tv2;
- int i, j;
-
- uint8_t *b = malloc(sz);
- if (!b) return -1;
- int c = 1000000000/sz;
-
- for (i = 0; iters == -1 || i < iters; i++) {
- gettimeofday(&tv1, NULL);
- for (j = 0; j < c; j++)
- memset(b, 0, sz);
-
- gettimeofday(&tv2, NULL);
-
- tv_sub(&tv2, &tv1);
-
- printf("memset %dx%d bytes took %ld.%06ld seconds (%f MB/s)\n",
- c, sz, tv2.tv_sec, tv2.tv_usec, mb_sec(c*sz, &tv2));
- }
- return 0;
-}
-
-static int do_memcpy(int iters, int sz) {
- struct timeval tv1;
- struct timeval tv2;
- int i, j;
-
- uint8_t *a = malloc(sz);
- if (!a) return -1;
- uint8_t *b = malloc(sz);
- if (!b) return -1;
- int c = 1000000000/sz;
-
- for (i = 0; iters == -1 || i < iters; i++) {
- gettimeofday(&tv1, NULL);
- for (j = 0; j < c; j++)
- memcpy(b, a, sz);
-
- gettimeofday(&tv2, NULL);
-
- tv_sub(&tv2, &tv1);
-
- printf("memcpy %dx%d bytes took %ld.%06ld seconds (%f MB/s)\n",
- c, sz, tv2.tv_sec, tv2.tv_usec, mb_sec(c*sz, &tv2));
- }
- return 0;
-}
-
-int foo;
-
-static int do_memread(int iters, int sz) {
- struct timeval tv1;
- struct timeval tv2;
- int i, j, k;
-
- int *b = malloc(sz);
- if (!b) return -1;
- int c = 1000000000/sz;
-
- for (i = 0; iters == -1 || i < iters; i++) {
- gettimeofday(&tv1, NULL);
- for (j = 0; j < c; j++)
- for (k = 0; k < sz/4; k++)
- foo = b[k];
-
- gettimeofday(&tv2, NULL);
-
- tv_sub(&tv2, &tv1);
-
- printf("read %dx%d bytes took %ld.%06ld seconds (%f MB/s)\n",
- c, sz, tv2.tv_sec, tv2.tv_usec, mb_sec(c*sz, &tv2));
- }
- return 0;
-}
-
-struct {
- char *name;
- int (*ptr)(int, int);
-} function_table[] = {
- {"sleep", do_sleep},
- {"cpu", do_cpu},
- {"memset", do_memset},
- {"memcpy", do_memcpy},
- {"memread", do_memread},
- {NULL, NULL},
-};
-
-static void usage() {
- int i;
-
- printf("Usage:\n");
- for (i = 0; function_table[i].name; i++) {
- printf("\tmicro_bench %s ARG [ITERS]\n", function_table[i].name);
- }
-}
-
-int main(int argc, char **argv) {
- int i;
- int iters;
-
- if (argc < 3 || argc > 4) {
- usage();
- return -1;
- }
- if (argc == 3) {
- iters = -1;
- } else {
- iters = atoi(argv[3]);
- }
- for (i = 0; function_table[i].name; i++) {
- if (!strcmp(argv[1], function_table[i].name)) {
- printf("%s\n", function_table[i].name);
- return (*function_table[i].ptr)(iters, atoi(argv[2]));
- }
- }
- usage();
- return -1;
-}
diff --git a/micro_bench/micro_bench.cpp b/micro_bench/micro_bench.cpp
new file mode 100644
index 0000000..b8d82f6
--- /dev/null
+++ b/micro_bench/micro_bench.cpp
@@ -0,0 +1,484 @@
+/*
+** Copyright 2010 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.
+*/
+
+/*
+ * Micro-benchmarking of sleep/cpu speed/memcpy/memset/memory reads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <time.h>
+#include <unistd.h>
+
+// The default size of data that will be manipulated in each iteration of
+// a memory benchmark. Can be modified with the --data_size option.
+#define DEFAULT_DATA_SIZE 1000000000
+
+// Number of nanoseconds in a second.
+#define NS_PER_SEC 1000000000
+
+// The maximum number of arguments that a benchmark will accept.
+#define MAX_ARGS 2
+
+// Use macros to compute values to try and avoid disturbing memory as much
+// as possible after each iteration.
+#define COMPUTE_AVERAGE_KB(avg_kb, bytes, time_ns) \
+ avg_kb = ((bytes) / 1024.0) / ((double)(time_ns) / NS_PER_SEC);
+
+#define COMPUTE_RUNNING(avg, running_avg, square_avg, cur_idx) \
+ running_avg = ((running_avg) / ((cur_idx) + 1)) * (cur_idx) + (avg) / ((cur_idx) + 1); \
+ square_avg = ((square_avg) / ((cur_idx) + 1)) * (cur_idx) + ((avg) / ((cur_idx) + 1)) * (avg);
+
+#define GET_STD_DEV(running_avg, square_avg) \
+ sqrt((square_avg) - (running_avg) * (running_avg))
+
+// Contains information about benchmark options.
+typedef struct {
+ bool print_average;
+ bool print_each_iter;
+
+ int dst_align;
+ int src_align;
+
+ int cpu_to_lock;
+
+ int data_size;
+
+ int args[MAX_ARGS];
+ int num_args;
+} command_data_t;
+
+// Struct that contains a mapping of benchmark name to benchmark function.
+typedef struct {
+ const char *name;
+ int (*ptr)(const command_data_t &cmd_data);
+} function_t;
+
+// Get the current time in nanoseconds.
+uint64_t nanoTime() {
+ struct timespec t;
+
+ t.tv_sec = t.tv_nsec = 0;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return static_cast<uint64_t>(t.tv_sec) * NS_PER_SEC + t.tv_nsec;
+}
+
+// Allocate memory with a specific alignment and return that pointer.
+// This function assumes an alignment value that is a power of 2.
+// If the alignment is 0, then use the pointer returned by malloc.
+uint8_t *allocateAlignedMemory(size_t size, int alignment) {
+ uint64_t ptr = reinterpret_cast<uint64_t>(malloc(size + 2 * alignment));
+ if (!ptr)
+ return NULL;
+ if (alignment > 0) {
+ // When setting the alignment, set it to exactly the alignment chosen.
+ // The pointer returned will be guaranteed not to be aligned to anything
+ // more than that.
+ ptr += alignment - (ptr & (alignment - 1));
+ ptr |= alignment;
+ }
+
+ return reinterpret_cast<uint8_t*>(ptr);
+}
+
+int benchmarkSleep(const command_data_t &cmd_data) {
+ uint64_t time_ns;
+
+ int delay = cmd_data.args[0];
+ int iters = cmd_data.args[1];
+ bool print_each_iter = cmd_data.print_each_iter;
+ bool print_average = cmd_data.print_average;
+ double avg, running_avg = 0.0, square_avg = 0.0;
+ for (int i = 0; iters == -1 || i < iters; i++) {
+ time_ns = nanoTime();
+ sleep(delay);
+ time_ns = nanoTime() - time_ns;
+
+ avg = (double)time_ns / NS_PER_SEC;
+
+ if (print_average) {
+ COMPUTE_RUNNING(avg, running_avg, square_avg, i);
+ }
+
+ if (print_each_iter) {
+ printf("sleep(%d) took %.06f seconds\n", delay, avg);
+ }
+ }
+
+ if (print_average) {
+ printf(" sleep(%d) average %.06f seconds std dev %f\n", delay,
+ running_avg, GET_STD_DEV(running_avg, square_avg));
+ }
+
+ return 0;
+}
+
+int benchmarkCpu(const command_data_t &cmd_data) {
+ // Use volatile so that the loop is not optimized away by the compiler.
+ volatile int cpu_foo;
+
+ uint64_t time_ns;
+ int iters = cmd_data.args[1];
+ bool print_each_iter = cmd_data.print_each_iter;
+ bool print_average = cmd_data.print_average;
+ double avg, running_avg = 0.0, square_avg = 0.0;
+ for (int i = 0; iters == -1 || i < iters; i++) {
+ time_ns = nanoTime();
+ for (cpu_foo = 0; cpu_foo < 100000000; cpu_foo++);
+ time_ns = nanoTime() - time_ns;
+
+ avg = (double)time_ns / NS_PER_SEC;
+
+ if (print_average) {
+ COMPUTE_RUNNING(avg, running_avg, square_avg, i);
+ }
+
+ if (print_each_iter) {
+ printf("cpu took %.06f seconds\n", avg);
+ }
+ }
+
+ if (print_average) {
+ printf(" cpu average %.06f seconds std dev %f\n",
+ running_avg, GET_STD_DEV(running_avg, square_avg));
+ }
+
+ return 0;
+}
+
+int benchmarkMemset(const command_data_t &cmd_data) {
+ int size = cmd_data.args[0];
+ int iters = cmd_data.args[1];
+
+ uint8_t *dst = allocateAlignedMemory(size, cmd_data.dst_align);
+ if (!dst)
+ return -1;
+
+ double avg_kb, running_avg_kb = 0.0, square_avg_kb = 0.0;
+ uint64_t time_ns;
+ int j;
+ bool print_average = cmd_data.print_average;
+ bool print_each_iter = cmd_data.print_each_iter;
+ int copies = cmd_data.data_size/size;
+ for (int i = 0; iters == -1 || i < iters; i++) {
+ time_ns = nanoTime();
+ for (j = 0; j < copies; j++)
+ memset(dst, 0, size);
+ time_ns = nanoTime() - time_ns;
+
+ // Compute in kb to avoid any overflows.
+ COMPUTE_AVERAGE_KB(avg_kb, copies * size, time_ns);
+
+ if (print_average) {
+ COMPUTE_RUNNING(avg_kb, running_avg_kb, square_avg_kb, i);
+ }
+
+ if (print_each_iter) {
+ printf("memset %dx%d bytes took %.06f seconds (%f MB/s)\n",
+ copies, size, (double)time_ns / NS_PER_SEC, avg_kb / 1024.0);
+ }
+ }
+
+ if (print_average) {
+ printf(" memset %dx%d bytes average %.2f MB/s std dev %.4f\n",
+ copies, size, running_avg_kb / 1024.0,
+ GET_STD_DEV(running_avg_kb, square_avg_kb) / 1024.0);
+ }
+ return 0;
+}
+
+int benchmarkMemcpy(const command_data_t &cmd_data) {
+ int size = cmd_data.args[0];
+ int iters = cmd_data.args[1];
+
+ uint8_t *src = allocateAlignedMemory(size, cmd_data.src_align);
+ if (!src)
+ return -1;
+ uint8_t *dst = allocateAlignedMemory(size, cmd_data.dst_align);
+ if (!dst)
+ return -1;
+
+ uint64_t time_ns;
+ double avg_kb, running_avg_kb = 0.0, square_avg_kb = 0.0;
+ int j;
+ bool print_average = cmd_data.print_average;
+ bool print_each_iter = cmd_data.print_each_iter;
+ int copies = cmd_data.data_size / size;
+ for (int i = 0; iters == -1 || i < iters; i++) {
+ time_ns = nanoTime();
+ for (j = 0; j < copies; j++)
+ memcpy(dst, src, size);
+ time_ns = nanoTime() - time_ns;
+
+ // Compute in kb to avoid any overflows.
+ COMPUTE_AVERAGE_KB(avg_kb, copies * size, time_ns);
+
+ if (print_average) {
+ COMPUTE_RUNNING(avg_kb, running_avg_kb, square_avg_kb, i);
+ }
+
+ if (print_each_iter) {
+ printf("memcpy %dx%d bytes took %.06f seconds (%f MB/s)\n",
+ copies, size, (double)time_ns / NS_PER_SEC, avg_kb / 1024.0);
+ }
+ }
+ if (print_average) {
+ printf(" memcpy %dx%d bytes average %.2f MB/s std dev %.4f\n",
+ copies, size, running_avg_kb/1024.0,
+ GET_STD_DEV(running_avg_kb, square_avg_kb) / 1024.0);
+ }
+ return 0;
+}
+
+int benchmarkMemread(const command_data_t &cmd_data) {
+ int size = cmd_data.args[0];
+ int iters = cmd_data.args[1];
+
+ int *src = reinterpret_cast<int*>(malloc(size));
+ if (!src)
+ return -1;
+
+ // Use volatile so the compiler does not optimize away the reads.
+ volatile int foo;
+ uint64_t time_ns;
+ int j, k;
+ double avg_kb, running_avg_kb = 0.0, square_avg_kb = 0.0;
+ bool print_average = cmd_data.print_average;
+ bool print_each_iter = cmd_data.print_each_iter;
+ int c = cmd_data.data_size / size;
+ for (int i = 0; iters == -1 || i < iters; i++) {
+ time_ns = nanoTime();
+ for (j = 0; j < c; j++)
+ for (k = 0; k < size/4; k++)
+ foo = src[k];
+ time_ns = nanoTime() - time_ns;
+
+ // Compute in kb to avoid any overflows.
+ COMPUTE_AVERAGE_KB(avg_kb, c * size, time_ns);
+
+ if (print_average) {
+ COMPUTE_RUNNING(avg_kb, running_avg_kb, square_avg_kb, i);
+ }
+
+ if (print_each_iter) {
+ printf("read %dx%d bytes took %.06f seconds (%f MB/s)\n",
+ c, size, (double)time_ns / NS_PER_SEC, avg_kb / 1024.0);
+ }
+ }
+
+ if (print_average) {
+ printf(" read %dx%d bytes average %.2f MB/s std dev %.4f\n",
+ c, size, running_avg_kb/1024.0,
+ GET_STD_DEV(running_avg_kb, square_avg_kb) / 1024.0);
+ }
+
+ return 0;
+}
+
+// Create the mapping structure.
+function_t function_table[] = {
+ { "sleep", benchmarkSleep },
+ { "cpu", benchmarkCpu },
+ { "memset", benchmarkMemset },
+ { "memcpy", benchmarkMemcpy },
+ { "memread", benchmarkMemread },
+ { NULL, NULL }
+};
+
+void usage() {
+ printf("Usage:\n");
+ printf(" micro_bench [--data_size DATA_BYTES] [--print_average]\n");
+ printf(" [--no_print_each_iter] [--lock_to_cpu CORE]\n");
+ printf(" --data_size DATA_BYTES\n");
+ printf(" For the data benchmarks (memcpy/memset/memread) the approximate\n");
+ printf(" size of data, in bytes, that will be manipulated in each iteration.\n");
+ printf(" --print_average\n");
+ printf(" Print the average and standard deviation of all iterations.\n");
+ printf(" --no_print_each_iter\n");
+ printf(" Do not print any values in each iteration.\n");
+ printf(" --lock_to_cpu CORE\n");
+ printf(" Lock to the specified CORE. The default is to use the last core found.\n");
+ printf(" ITERS\n");
+ printf(" The number of iterations to execute each benchmark. If not\n");
+ printf(" passed in then run forever.\n");
+ printf(" micro_bench sleep TIME_TO_SLEEP [ITERS]\n");
+ printf(" TIME_TO_SLEEP\n");
+ printf(" The time in seconds to sleep.\n");
+ printf(" micro_bench cpu UNUSED [ITERS]\n");
+ printf(" micro_bench [--dst_align ALIGN] memset NUM_BYTES [ITERS]\n");
+ printf(" --dst_align ALIGN\n");
+ printf(" Align the memset destination pointer to ALIGN. The default is to use the\n");
+ printf(" value returned by malloc.\n");
+ printf(" micro_bench [--src_align ALIGN] [--dst_align ALIGN] memcpy NUM_BYTES [ITERS]\n");
+ printf(" --src_align ALIGN\n");
+ printf(" Align the memcpy source pointer to ALIGN. The default is to use the\n");
+ printf(" value returned by malloc.\n");
+ printf(" --dst_align ALIGN\n");
+ printf(" Align the memcpy destination pointer to ALIGN. The default is to use the\n");
+ printf(" value returned by malloc.\n");
+ printf(" micro_bench memread NUM_BYTES [ITERS]\n");
+}
+
+function_t *processOptions(int argc, char **argv, command_data_t *cmd_data) {
+ function_t *command = NULL;
+
+ // Initialize the command_flags.
+ cmd_data->print_average = false;
+ cmd_data->print_each_iter = true;
+ cmd_data->dst_align = 0;
+ cmd_data->src_align = 0;
+ cmd_data->num_args = 0;
+ cmd_data->cpu_to_lock = -1;
+ cmd_data->data_size = DEFAULT_DATA_SIZE;
+ for (int i = 0; i < MAX_ARGS; i++) {
+ cmd_data->args[i] = -1;
+ }
+
+ for (int i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ int *save_value = NULL;
+ if (strcmp(argv[i], "--print_average") == 0) {
+ cmd_data->print_average = true;
+ } else if (strcmp(argv[i], "--no_print_each_iter") == 0) {
+ cmd_data->print_each_iter = false;
+ } else if (strcmp(argv[i], "--dst_align") == 0) {
+ save_value = &cmd_data->dst_align;
+ } else if (strcmp(argv[i], "--src_align") == 0) {
+ save_value = &cmd_data->src_align;
+ } else if (strcmp(argv[i], "--lock_to_cpu") == 0) {
+ save_value = &cmd_data->cpu_to_lock;
+ } else if (strcmp(argv[i], "--data_size") == 0) {
+ save_value = &cmd_data->data_size;
+ } else {
+ printf("Unknown option %s\n", argv[i]);
+ return NULL;
+ }
+ if (save_value) {
+ // Checking both characters without a strlen() call should be
+ // safe since as long as the argument exists, one character will
+ // be present (\0). And if the first character is '-', then
+ // there will always be a second character (\0 again).
+ if (i == argc - 1 || (argv[i + 1][0] == '-' && !isdigit(argv[i + 1][1]))) {
+ printf("The option %s requires one argument.\n",
+ argv[i]);
+ return NULL;
+ }
+ *save_value = atoi(argv[++i]);
+ }
+ } else if (!command) {
+ for (function_t *function = function_table; function->name != NULL; function++) {
+ if (strcmp(argv[i], function->name) == 0) {
+ command = function;
+ break;
+ }
+ }
+ if (!command) {
+ printf("Uknown command %s\n", argv[i]);
+ return NULL;
+ }
+ } else if (cmd_data->num_args > MAX_ARGS) {
+ printf("More than %d number arguments passed in.\n", MAX_ARGS);
+ return NULL;
+ } else {
+ cmd_data->args[cmd_data->num_args++] = atoi(argv[i]);
+ }
+ }
+
+ // Check the arguments passed in make sense.
+ if (cmd_data->num_args != 1 && cmd_data->num_args != 2) {
+ printf("Not enough arguments passed in.\n");
+ return NULL;
+ } else if (cmd_data->dst_align < 0) {
+ printf("The --dst_align option must be greater than or equal to 0.\n");
+ return NULL;
+ } else if (cmd_data->src_align < 0) {
+ printf("The --src_align option must be greater than or equal to 0.\n");
+ return NULL;
+ } else if (cmd_data->data_size <= 0) {
+ printf("The --data_size option must be a positive number.\n");
+ return NULL;
+ } else if ((cmd_data->dst_align & (cmd_data->dst_align - 1))) {
+ printf("The --dst_align option must be a power of 2.\n");
+ return NULL;
+ } else if ((cmd_data->src_align & (cmd_data->src_align - 1))) {
+ printf("The --src_align option must be a power of 2.\n");
+ return NULL;
+ }
+
+ return command;
+}
+
+bool raisePriorityAndLock(int cpu_to_lock) {
+ cpu_set_t cpuset;
+
+ if (setpriority(PRIO_PROCESS, 0, -20)) {
+ perror("Unable to raise priority of process.\n");
+ return false;
+ }
+
+ CPU_ZERO(&cpuset);
+ if (sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+ perror("sched_getaffinity failed");
+ return false;
+ }
+
+ if (cpu_to_lock < 0) {
+ // Lock to the last active core we find.
+ for (int i = 0; i < CPU_SETSIZE; i++) {
+ if (CPU_ISSET(i, &cpuset)) {
+ cpu_to_lock = i;
+ }
+ }
+ } else if (!CPU_ISSET(cpu_to_lock, &cpuset)) {
+ printf("Cpu %d does not exist.\n", cpu_to_lock);
+ return false;
+ }
+
+ if (cpu_to_lock < 0) {
+ printf("Cannot find any valid cpu to lock.\n");
+ return false;
+ }
+
+ CPU_ZERO(&cpuset);
+ CPU_SET(cpu_to_lock, &cpuset);
+ if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+ perror("sched_setaffinity failed");
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv) {
+ command_data_t cmd_data;
+
+ function_t *command = processOptions(argc, argv, &cmd_data);
+ if (!command) {
+ usage();
+ return -1;
+ }
+
+ if (!raisePriorityAndLock(cmd_data.cpu_to_lock)) {
+ return -1;
+ }
+
+ printf("%s\n", command->name);
+ return (*command->ptr)(cmd_data);
+}
diff --git a/tests/bionic/libc/Android.mk b/tests/bionic/libc/Android.mk
index 52ef01e..fc3a00e 100644
--- a/tests/bionic/libc/Android.mk
+++ b/tests/bionic/libc/Android.mk
@@ -152,9 +152,7 @@
sources := \
other/bench_locks.c \
- other/test_aligned.c \
other/test_arc4random.c \
- other/test_atomics.c \
other/test_sysconf.c \
other/test_system.c \
other/test_thread_max.c \
@@ -163,6 +161,11 @@
other/test_timer_create3.c \
other/test_vfprintf_leak.c \
+ifeq ($(TARGET_ARCH),arm)
+sources += \
+ other/test_atomics.c
+endif
+
$(call device-test, $(sources))
# The relocations test is a bit special, since we need
diff --git a/tests/bionic/libc/other/test_aligned.c b/tests/bionic/libc/other/test_aligned.c
deleted file mode 100644
index 8a66dd6..0000000
--- a/tests/bionic/libc/other/test_aligned.c
+++ /dev/null
@@ -1,117 +0,0 @@
-#include <stdio.h>
-#include <arpa/inet.h> /* for htons() etc.. */
-
-static char tab[8];
-
-static void
-read4( int o, unsigned val )
-{
- unsigned v = htonl(val);
- unsigned v2;
-
- tab[o+0] = (char)(v >> 24);
- tab[o+1] = (char)(v >> 16);
- tab[o+2] = (char)(v >> 8);
- tab[o+3] = (char)(v);
-
- printf( "read4: offset=%d value=%08x: ", o, val );
- fflush(stdout);
-
- v2 = *(unsigned*)(tab+o);
-
- if (v2 != val) {
- printf( "FAIL (%08x)\n", v2 );
- } else {
- printf( "ok\n" );
- }
-}
-
-static void
-writ4( int o, unsigned val )
-{
- unsigned v = htonl(val);
- unsigned v2;
-
- printf( "writ4: offset=%d value=%08x: ", o, val );
- fflush(stdout);
-
- *(unsigned*)(tab+o) = v;
-
- v2 = ((unsigned)tab[o+0] << 24) |
- ((unsigned)tab[o+1] << 16) |
- ((unsigned)tab[o+2] << 8 ) |
- ((unsigned)tab[o+3] );
-
- if (v2 != val) {
- printf( "FAIL (%08x)\n", v2 );
- } else {
- printf( "ok\n" );
- }
-}
-
-static void
-read2( int o, unsigned val )
-{
- unsigned short v = htons(val);
- unsigned short v2;
-
- tab[o+0] = (char)(v >> 8);
- tab[o+1] = (char)(v);
-
- printf( "read2: offset=%d value=%08x: ", o, val );
- fflush(stdout);
-
- v2 = *(unsigned short*)(tab+o);
-
- if (v2 != val) {
- printf( "FAIL (%04x)\n", v2 );
- } else {
- printf( "ok\n" );
- }
-}
-
-static void
-writ2( int o, unsigned val )
-{
- unsigned short v = htons(val);
- unsigned short v2;
-
- printf( "writ2: offset=%d value=%08x: ", o, val );
- fflush(stdout);
-
- *(unsigned short*)(tab+o) = v;
-
- v2 = ((unsigned)tab[o+0] << 8) |
- ((unsigned)tab[o+1] );
-
- if (v2 != val) {
- printf( "FAIL (%08x)\n", v2 );
- } else {
- printf( "ok\n" );
- }
-}
-
-
-
-int main(void)
-{
- read4( 0, 0x12345678 );
- writ4( 0, 0x12345678 );
- read4( 1, 0x12345678 );
- writ4( 1, 0x12345678 );
- read4( 2, 0x12345678 );
- writ4( 2, 0x12345678 );
- read4( 3, 0x12345678 );
- writ4( 3, 0x12345678 );
-
- read2( 0, 0x1234 );
- writ2( 0, 0x1234 );
- read2( 1, 0x1234 );
- writ2( 1, 0x1234 );
- read2( 2, 0x1234 );
- writ2( 2, 0x1234 );
- read2( 3, 0x1234 );
- writ2( 3, 0x1234 );
-
- return 0;
-}