--- /dev/null
+// Copyright 2017 The Android Open Source Project
+
+subdirs = [
+ "contrib",
+ "debugfs",
+ "e2fsck",
+ "lib",
+ "misc",
+ "resize",
+]
+++ /dev/null
-include $(call all-subdir-makefiles)
check::
+fullcheck::
+
SHELL = /bin/sh
COMPRESS_EXT = gz bz2 bz Z
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//'`; \
check:: all check-recursive
+fullcheck:: all fullcheck-recursive
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"
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"
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
fallocate
fallocate64
fchown
+ fcntl
fdatasync
fstat64
+ fsync
ftruncate64
futimes
getcwd
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
-
--- /dev/null
+// 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"],
+ },
+ },
+}
--- /dev/null
+#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(¶ms->entry.head, ¶ms->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,
+};
--- /dev/null
+#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 */
--- /dev/null
+#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;
+}
--- /dev/null
+#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 */
--- /dev/null
+#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(¶ms->entry.head, ¶ms->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,
+};
--- /dev/null
+#ifndef BLOCK_LIST_H
+# define BLOCK_LIST_H
+
+# include "fsmap.h"
+
+extern struct fsmap_format block_list_format;
+
+#endif /* !BLOCK_LIST_H */
--- /dev/null
+#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;
+}
--- /dev/null
+#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 */
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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 */
--- /dev/null
+#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);
+}
--- /dev/null
+#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 */
--- /dev/null
+#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(¶ms->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, ¶ms);
+ if (retval)
+ return retval;
+ retval = set_timestamp(fs, EXT2_ROOT_INO, ¶ms);
+ if (retval)
+ return retval;
+
+ return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir,
+ ¶ms);
+}
+
+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);
+}
--- /dev/null
+#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 */
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
$(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 +++
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");
}
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,
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;
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",
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;
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,
/* 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 },
}
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)
if (err)
goto out;
}
-
- err = ext2fs_xattrs_write(h);
- if (err)
- goto out;
out:
ext2fs_xattrs_close(&h);
if (err)
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
$(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
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;
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;
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
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);
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 */
* 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;
};
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;
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);
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;
* 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) {
}
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;
}
* 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;
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)
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;
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;
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;
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++;
}
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;
}
}
{
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) {
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:
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);
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:
* %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>
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);
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));
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)
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);
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);
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));
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);
* - 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);
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);
struct process_inode_block {
ext2_ino_t ino;
+ struct ea_quota ea_ibody_quota;
struct ext2_inode_large inode;
};
{
unsigned int len;
int i;
- blk64_t blocks;
ext2_extent_handle_t handle;
struct ext2_extent_info info;
struct ext2fs_extent extent;
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;
}
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)
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;
/* 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,
+ "a_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);
}
* 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) {
*/
#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 */
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 */
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);
}
/*
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);
"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;
}
"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;
}
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;
}
}
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) &&
}
}
- check_inode_extra_space(ctx, &pctx);
+ check_inode_extra_space(ctx, &pctx, &ea_ibody_quota);
check_is_really_dir(ctx, &pctx, block_buf);
/*
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;
}
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);
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);
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;
}
}
}
+/*
+ * 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);
+ }
}
/*
ext2_filsys fs = ctx->fs;
blk64_t blk;
__u32 should_be;
- int count;
+ ea_value_t count;
clear_problem_context(&pctx);
}
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;
* 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;
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;
/* 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,
+ "a_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 */
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;
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);
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;
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;
{
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;
}
}
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 */
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 &&
* 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;
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;
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))
}
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) ||
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;
* 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;
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)
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;
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;
} 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++;
* 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"
"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);
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)
{
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,
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:
#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);
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 */
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 */
"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 */
e2_blkcnt_t blkcount;
dgrp_t group;
__u32 csum1, csum2;
- __u64 num;
+ __u64 num, num2;
const char *str;
};
/* 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
*/
/* 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
/* 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
*/
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.
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) +
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++) {
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)
}
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);
__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 {
__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 {
__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 */
#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;
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 */
$(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
--- /dev/null
+// 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 = [
+ "*",
+]
+++ /dev/null
-include $(call all-subdir-makefiles)
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
$(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
{
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;
/* 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
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
$(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
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
$(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 ; \
#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
*/
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;
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;
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
$(TDB_OBJ) \
undo_io.o \
unix_io.o \
+ sparse_io.o \
unlink.o \
valid_blk.o \
version.o \
$(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 \
$(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
$(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 \
* 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;
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)
{
* 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;
goto fail;
}
- retval = ext2fs_new_block2(fs, goal, 0, &block);
+ retval = ext2fs_new_block3(fs, goal, 0, &block, ctx);
if (retval)
goto 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,
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) {
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,
* %End-Header%
*/
+#include "config.h"
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#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"
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;
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);
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;
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;
}
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;
}
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;
}
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;
{
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));
}
__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
__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 {
__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 {
#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) \
#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| \
#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.
*/
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);
#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 {
*/
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);
/*
#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
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|\
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,
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,
/* 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);
#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);
/* 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);
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)
*/
#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
}
/* 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--) {
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 &&
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)
{
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,
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;
{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;
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;
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);
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;
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);
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;
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;
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;
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;
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,
(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);
}
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)
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:
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;
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;
}
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) &&
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;
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);
}
}
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);
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);
* 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;
}
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)) {
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;
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;
#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 ""
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;
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)
--- /dev/null
+#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;
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);
}
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);
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) {
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);
+}
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;
int fd_flags;
fd = atoi(str_fd);
+#if defined(HAVE_FCNTL)
fd_flags = fcntl(fd, F_GETFD);
if (fd_flags == -1)
return -EBADF;
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);
}
#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;
}
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
$(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 \
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
../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
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
../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
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
-
$(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
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;
errcode_t retval = 0;
int read_cnt;
int hdlink;
+ size_t cur_dir_path_len;
if (chdir(source_dir) < 0) {
retval = errno;
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:
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("..")) {
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) {
/*
hdlinks->hdl[hdlinks->count].dst_ino = ino;
hdlinks->count++;
}
+ target->path_len = cur_dir_path_len;
+ target->path[target->path_len] = 0;
}
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;
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);
+}
#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,
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] "
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";
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 /
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);
}
--- /dev/null
+/*
+ * 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
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);
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)) {
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)
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);
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);
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;
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);
badopt = token;
continue;
}
+ } else if (!strcmp(token, "android_sparse")) {
+ android_sparse_file = 1;
} else {
r_usage++;
badopt = token;
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|
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);
"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 */
*/
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"));
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|
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)
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);
}
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;
}
done; \
done
-check: all
+fullcheck check: all
info dvi ps pdf html tags TAGS ctags CTAGS ID:
"#. %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",
--- /dev/null
+// 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"],
+}
+++ /dev/null
-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)
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 \
{
}
+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;
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) &&
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)
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:
@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)
check:: test_pre test_post test_script
+fullcheck::
+ $(MAKE) SKIP_SLOW_TESTS= check
+
check-failed: $(basename $(wildcard *.failed))
@$(srcdir)/test_post
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+optimize 3 level htree directories
--- /dev/null
+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
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.
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
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"
-/* 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
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"
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