indirect.c \
uuid.c \
sha1.c \
- sparse_crc32.c
+ sparse_crc32.c \
+ wipe.c
LOCAL_SRC_FILES := $(libext4_utils_src_files)
LOCAL_MODULE := libext4_utils
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES += external/zlib
LOCAL_SHARED_LIBRARIES := libz
-LOCAL_PRELINK_MODULE := false
+
include $(BUILD_SHARED_LIBRARY)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES += external/zlib
LOCAL_STATIC_LIBRARIES := libz
-LOCAL_PRELINK_MODULE := false
+
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
+LOCAL_SRC_FILES := ext2simg.c
+LOCAL_MODULE := ext2simg
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES += libext4_utils libz
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := ext2simg.c
+LOCAL_MODULE := ext2simg
+LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_LIBRARIES += libext4_utils libz
+
+include $(BUILD_HOST_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
LOCAL_SRC_FILES := simg2img.c \
sparse_crc32.c
LOCAL_MODULE := simg2img
include $(CLEAR_VARS)
+LOCAL_SRC_FILES := simg2img.c \
+ sparse_crc32.c
+LOCAL_MODULE := simg2img
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
LOCAL_MODULE := mkuserimg.sh
LOCAL_SRC_FILES := mkuserimg.sh
LOCAL_MODULE_CLASS := EXECUTABLES
* limitations under the License.
*/
-#include <stdio.h>
-#include <stdlib.h>
-
#include "ext4_utils.h"
#include "allocate.h"
#include "backed_block.h"
#include "ext4.h"
+#include <stdio.h>
+#include <stdlib.h>
+
struct region_list {
struct region *first;
struct region *last;
u32 block = bg->first_block + 2;
if (bg->has_superblock)
- block += aux_info.bg_desc_blocks + aux_info.bg_desc_reserve_blocks + 1;
+ block += aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks + 1;
bg->inode_table = calloc(aux_info.inode_table_blocks, info.block_size);
if (bg->inode_table == NULL)
bg->has_superblock = ext4_bg_has_super_block(i);
if (bg->has_superblock)
- header_blocks += 1 + aux_info.bg_desc_blocks + aux_info.bg_desc_reserve_blocks;
+ header_blocks += 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
bg->bitmaps = calloc(info.block_size, 2);
bg->block_bitmap = bg->bitmaps;
u32 block = bg->first_block;
if (bg->has_superblock)
- block += 1 + aux_info.bg_desc_blocks + aux_info.bg_desc_reserve_blocks;
+ block += 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
queue_data_block(bg->bitmaps, 2 * info.block_size, block);
bg->data_blocks_used = 0;
* limitations under the License.
*/
+#ifndef _ALLOCATE_H_
+#define _ALLOCATE_H_
+
#define EXT4_ALLOCATE_FAILED (u32)(~0)
#include "ext4_utils.h"
u32 block, u32 len, int bg);
struct block_allocation *create_allocation();
int append_oob_allocation(struct block_allocation *alloc, u32 len);
+
+#endif
* limitations under the License.
*/
-#include <stdlib.h>
-
#include "ext4_utils.h"
#include "backed_block.h"
+#include <stdlib.h>
+
struct data_block {
u32 block;
u32 len;
u8 *data;
const char *filename;
- off_t offset;
+ off64_t offset;
struct data_block *next;
};
}
/* Queues a chunk of a file on disk to be written to the specified data blocks */
-void queue_data_file(const char *filename, off_t offset, u32 len,
+void queue_data_file(const char *filename, off64_t offset, u32 len,
u32 block)
{
struct data_block *db = malloc(sizeof(struct data_block));
/* Iterates over the queued data blocks, calling data_func for each contiguous
data block, and file_func for each contiguous file block */
void for_each_data_block(data_block_callback_t data_func,
- data_block_file_callback_t file_func, struct output_file *out)
+ data_block_file_callback_t file_func, void *priv)
{
struct data_block *db;
u32 last_block = 0;
last_block = db->block + DIV_ROUND_UP(db->len, info.block_size) - 1;
if (db->filename)
- file_func(out, (u64)db->block * info.block_size, db->filename, db->offset, db->len);
+ file_func(priv, (u64)db->block * info.block_size, db->filename, db->offset, db->len);
else
- data_func(out, (u64)db->block * info.block_size, db->data, db->len);
+ data_func(priv, (u64)db->block * info.block_size, db->data, db->len);
}
}
#ifndef _BACKED_BLOCK_H_
#define _BACKED_BLOCK_H_
-#include <sys/types.h>
-#include <unistd.h>
#include "ext4_utils.h"
#include "output_file.h"
-typedef void (*data_block_callback_t)(struct output_file *out, u64 off,
- u8 *data, int len);
-typedef void (*data_block_file_callback_t)(struct output_file *out, u64 off,
- const char *file, off_t offset,
+typedef void (*data_block_callback_t)(void *priv, u64 off, u8 *data, int len);
+typedef void (*data_block_file_callback_t)(void *priv, u64 off,
+ const char *file, off64_t offset,
int len);
void queue_data_block(u8 *data, u32 len, u32 block);
-void queue_data_file(const char *filename, off_t offset, u32 len,
+void queue_data_file(const char *filename, off64_t offset, u32 len,
u32 block);
void for_each_data_block(data_block_callback_t data_func,
- data_block_file_callback_t file_func, struct output_file *out);
+ data_block_file_callback_t file_func, void *priv);
void free_data_blocks();
#endif
len += dentry_len;
}
+ /* include size of the dentry used to pad until the end of the block */
+ if (len % info.block_size + 8 > info.block_size)
+ len += info.block_size - (len % info.block_size);
+ len += 8;
+
return len;
}
struct ext4_dir_entry_2 *dentry;
u32 start_block = *offset / info.block_size;
- u32 end_block = (*offset + rec_len) / info.block_size;
+ u32 end_block = (*offset + rec_len - 1) / info.block_size;
if (start_block != end_block) {
/* Adding this dentry will cross a block boundary, so pad the previous
dentry to the block boundary */
data = inode_allocate_data_extents(inode, len, len);
if (data == NULL) {
- error("failed to allocate %llu extents", len);
+ error("failed to allocate %u extents", len);
return EXT4_ALLOCATE_FAILED;
}
--- /dev/null
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ext4_utils.h"
+#include "make_ext4fs.h"
+#include "output_file.h"
+#include "backed_block.h"
+#include "allocate.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <unistd.h>
+
+extern struct fs_info info;
+
+static int verbose = 0;
+
+static void usage(char *path)
+{
+ fprintf(stderr, "%s [ options ] <image or block device> <output image>\n", path);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " -c include CRC block\n");
+ fprintf(stderr, " -v verbose output\n");
+ fprintf(stderr, " -z gzip output\n");
+ fprintf(stderr, " -S don't use sparse output format\n");
+}
+
+static int read_ext(int fd)
+{
+ off64_t ret;
+ struct ext4_super_block sb;
+ unsigned int i;
+
+ ret = lseek64(fd, 1024, SEEK_SET);
+ if (ret < 0)
+ critical_error_errno("failed to seek to superblock");
+
+ ret = read(fd, &sb, sizeof(sb));
+ if (ret < 0)
+ critical_error_errno("failed to read superblock");
+ if (ret != sizeof(sb))
+ critical_error("failed to read all of superblock");
+
+ ext4_parse_sb(&sb);
+
+ ret = lseek64(fd, info.len, SEEK_SET);
+ if (ret < 0)
+ critical_error_errno("failed to seek to end of input image");
+
+ ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
+ if (ret < 0)
+ critical_error_errno("failed to seek to block group descriptors");
+
+ ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
+ if (ret < 0)
+ critical_error_errno("failed to read block group descriptors");
+ if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
+ critical_error("failed to read all of block group descriptors");
+
+ if (verbose) {
+ printf("Found filesystem with parameters:\n");
+ printf(" Size: %llu\n", info.len);
+ printf(" Block size: %d\n", info.block_size);
+ printf(" Blocks per group: %d\n", info.blocks_per_group);
+ printf(" Inodes per group: %d\n", info.inodes_per_group);
+ printf(" Inode size: %d\n", info.inode_size);
+ printf(" Label: %s\n", info.label);
+ printf(" Blocks: %llu\n", aux_info.len_blocks);
+ printf(" Block groups: %d\n", aux_info.groups);
+ printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
+ printf(" Used %d/%d inodes and %d/%d blocks\n",
+ aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
+ aux_info.sb->s_inodes_count,
+ aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
+ aux_info.sb->s_blocks_count_lo);
+ }
+
+ return 0;
+}
+
+static int bitmap_get_bit(u8 *bitmap, u32 bit)
+{
+ if (bitmap[bit / 8] & 1 << (bit % 8))
+ return 1;
+
+ return 0;
+}
+
+static int build_sparse_ext(int fd, const char *filename)
+{
+ unsigned int i;
+ unsigned int block;
+ int start_contiguous_block;
+ u8 *block_bitmap;
+ off64_t ret;
+
+ block_bitmap = malloc(info.block_size);
+ if (!block_bitmap)
+ critical_error("failed to allocate block bitmap");
+
+ if (aux_info.first_data_block > 0)
+ queue_data_file(filename, 0,
+ info.block_size * aux_info.first_data_block, 0);
+
+ for (i = 0; i < aux_info.groups; i++) {
+ u32 first_block = aux_info.first_data_block + i * info.blocks_per_group;
+ u32 last_block = min(info.blocks_per_group, aux_info.len_blocks - first_block);
+
+ ret = lseek64(fd, (u64)info.block_size * aux_info.bg_desc[i].bg_block_bitmap,
+ SEEK_SET);
+ if (ret < 0)
+ critical_error_errno("failed to seek to block group bitmap %d", i);
+
+ ret = read(fd, block_bitmap, info.block_size);
+ if (ret < 0)
+ critical_error_errno("failed to read block group bitmap %d", i);
+ if (ret != (int)info.block_size)
+ critical_error("failed to read all of block group bitmap %d", i);
+
+ start_contiguous_block = -1;
+ for (block = 0; block < last_block; block++) {
+ if (start_contiguous_block >= 0) {
+ if (!bitmap_get_bit(block_bitmap, block)) {
+ u32 start_block = first_block + start_contiguous_block;
+ u32 len_blocks = block - start_contiguous_block;
+
+ queue_data_file(filename, (u64)info.block_size * start_block,
+ info.block_size * len_blocks, start_block);
+ start_contiguous_block = -1;
+ }
+ } else {
+ if (bitmap_get_bit(block_bitmap, block))
+ start_contiguous_block = block;
+ }
+ }
+
+ if (start_contiguous_block >= 0) {
+ u32 start_block = first_block + start_contiguous_block;
+ u32 len_blocks = last_block - start_contiguous_block;
+ queue_data_file(filename, (u64)info.block_size * start_block,
+ info.block_size * len_blocks, start_block);
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int opt;
+ const char *in = NULL;
+ const char *out = NULL;
+ int gzip = 0;
+ int sparse = 1;
+ int fd;
+ int crc = 0;
+
+ while ((opt = getopt(argc, argv, "cvzS")) != -1) {
+ switch (opt) {
+ case 'c':
+ crc = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'z':
+ gzip = 1;
+ break;
+ case 'S':
+ sparse = 0;
+ break;
+ }
+ }
+
+ if (optind >= argc) {
+ fprintf(stderr, "Expected image or block device after options\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ in = argv[optind++];
+
+ if (optind >= argc) {
+ fprintf(stderr, "Expected output image after input image\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ out = argv[optind++];
+
+ if (optind < argc) {
+ fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ fd = open(in, O_RDONLY);
+
+ if (fd < 0)
+ critical_error_errno("failed to open input image");
+
+ read_ext(fd);
+
+ build_sparse_ext(fd, in);
+
+ close(fd);
+
+ write_ext4_image(out, gzip, sparse, crc, 0);
+
+ return 0;
+}
* limitations under the License.
*/
+#include "ext4_utils.h"
+#include "output_file.h"
+#include "backed_block.h"
+#include "uuid.h"
+#include "allocate.h"
+#include "indirect.h"
+#include "extent.h"
+
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/disk.h>
#endif
-#include "ext4_utils.h"
-#include "output_file.h"
-#include "backed_block.h"
-#include "uuid.h"
-#include "allocate.h"
-#include "indirect.h"
-#include "extent.h"
-
#include "ext4.h"
#include "jbd2.h"
struct fs_info info;
struct fs_aux_info aux_info;
+jmp_buf setjmp_env;
+
/* returns 1 if a is a power of b */
static int is_power_of(int a, int b)
{
return 0;
}
+struct count_chunks {
+ u32 chunks;
+ u64 cur_ptr;
+};
+
+void count_data_block(void *priv, u64 off, u8 *data, int len)
+{
+ struct count_chunks *count_chunks = priv;
+ if (off > count_chunks->cur_ptr)
+ count_chunks->chunks++;
+ count_chunks->cur_ptr = off + ALIGN(len, info.block_size);
+ count_chunks->chunks++;
+}
+
+void count_file_block(void *priv, u64 off, const char *file,
+ off64_t offset, int len)
+{
+ struct count_chunks *count_chunks = priv;
+ if (off > count_chunks->cur_ptr)
+ count_chunks->chunks++;
+ count_chunks->cur_ptr = off + ALIGN(len, info.block_size);
+ count_chunks->chunks++;
+}
+
+int count_sparse_chunks()
+{
+ struct count_chunks count_chunks = {0, 0};
+
+ for_each_data_block(count_data_block, count_file_block, &count_chunks);
+
+ if (count_chunks.cur_ptr != (u64) info.len)
+ count_chunks.chunks++;
+
+ return count_chunks.chunks;
+}
+
+static void ext4_write_data_block(void *priv, u64 off, u8 *data, int len)
+{
+ write_data_block(priv, off, data, len);
+}
+static void ext4_write_data_file(void *priv, u64 off, const char *file,
+ off64_t offset, int len)
+{
+ write_data_file(priv, off, file, offset, len);
+}
+
/* Write the filesystem image to a file */
-void write_ext4_image(const char *filename, int gz, int sparse)
+void write_ext4_image(const char *filename, int gz, int sparse, int crc,
+ int wipe)
{
int ret = 0;
- struct output_file *out = open_output_file(filename, gz, sparse);
- off_t off;
+ struct output_file *out = open_output_file(filename, gz, sparse,
+ count_sparse_chunks(), crc, wipe);
if (!out)
return;
- /* The write_data* functions expect only block aligned calls.
- * This is not an issue, except when we write out the super
- * block on a system with a block size > 1K. So, we need to
- * deal with that here.
- */
- if (info.block_size > 1024) {
- u8 buf[4096] = { 0 }; /* The larget supported ext4 block size */
- memcpy(buf + 1024, (u8*)aux_info.sb, 1024);
- write_data_block(out, 0, buf, info.block_size);
-
- } else {
- write_data_block(out, 1024, (u8*)aux_info.sb, 1024);
- }
-
- write_data_block(out, (u64)(aux_info.first_data_block + 1) * info.block_size,
- (u8*)aux_info.bg_desc,
- aux_info.bg_desc_blocks * info.block_size);
-
- for_each_data_block(write_data_block, write_data_file, out);
+ for_each_data_block(ext4_write_data_block, ext4_write_data_file, out);
pad_output_file(out, info.len);
DIV_ROUND_UP(aux_info.groups * sizeof(struct ext2_group_desc),
info.block_size);
- aux_info.bg_desc_reserve_blocks =
- DIV_ROUND_UP(aux_info.groups * 1024 * sizeof(struct ext2_group_desc),
- info.block_size) - aux_info.bg_desc_blocks;
-
- if (aux_info.bg_desc_reserve_blocks > aux_info.blocks_per_ind)
- aux_info.bg_desc_reserve_blocks = aux_info.blocks_per_ind;
-
aux_info.default_i_flags = EXT4_NOATIME_FL;
u32 last_group_size = aux_info.len_blocks % info.blocks_per_group;
u32 last_header_size = 2 + aux_info.inode_table_blocks;
if (ext4_bg_has_super_block(aux_info.groups - 1))
last_header_size += 1 + aux_info.bg_desc_blocks +
- aux_info.bg_desc_reserve_blocks;
+ info.bg_desc_reserve_blocks;
if (last_group_size > 0 && last_group_size < last_header_size) {
aux_info.groups--;
aux_info.len_blocks -= last_group_size;
memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
sb->s_algorithm_usage_bitmap = 0;
- sb->s_reserved_gdt_blocks = aux_info.bg_desc_reserve_blocks;
+ sb->s_reserved_gdt_blocks = info.bg_desc_reserve_blocks;
sb->s_prealloc_blocks = 0;
sb->s_prealloc_dir_blocks = 0;
info.blocks_per_group;
u32 header_size = 0;
if (ext4_bg_has_super_block(i)) {
- if (i != 0) {
+ if (i != 0)
queue_data_block((u8 *)sb, info.block_size, group_start_block);
- queue_data_block((u8 *)aux_info.bg_desc,
- aux_info.bg_desc_blocks * info.block_size,
- group_start_block + 1);
- }
- header_size = 1 + aux_info.bg_desc_blocks + aux_info.bg_desc_reserve_blocks;
+ queue_data_block((u8 *)aux_info.bg_desc,
+ aux_info.bg_desc_blocks * info.block_size,
+ group_start_block + 1);
+ header_size = 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
}
aux_info.bg_desc[i].bg_block_bitmap = group_start_block + header_size;
}
}
+void ext4_queue_sb(void)
+{
+ /* The write_data* functions expect only block aligned calls.
+ * This is not an issue, except when we write out the super
+ * block on a system with a block size > 1K. So, we need to
+ * deal with that here.
+ */
+ if (info.block_size > 1024) {
+ u8 *buf = calloc(info.block_size, 1);
+ memcpy(buf + 1024, (u8*)aux_info.sb, 1024);
+ queue_data_block(buf, info.block_size, 0);
+ } else {
+ queue_data_block((u8*)aux_info.sb, 1024, 1);
+ }
+}
+
+void ext4_parse_sb(struct ext4_super_block *sb)
+{
+ if (sb->s_magic != EXT4_SUPER_MAGIC)
+ error("superblock magic incorrect");
+
+ if (sb->s_state != EXT4_VALID_FS)
+ error("filesystem state not valid");
+
+ info.block_size = 1024 << sb->s_log_block_size;
+ info.blocks_per_group = sb->s_blocks_per_group;
+ info.inodes_per_group = sb->s_inodes_per_group;
+ info.inode_size = sb->s_inode_size;
+ info.inodes = sb->s_inodes_count;
+ info.feat_ro_compat = sb->s_feature_ro_compat;
+ info.feat_compat = sb->s_feature_compat;
+ info.feat_incompat = sb->s_feature_incompat;
+ info.bg_desc_reserve_blocks = sb->s_reserved_gdt_blocks;
+ info.label = sb->s_volume_name;
+
+ aux_info.len_blocks = ((u64)sb->s_blocks_count_hi << 32) +
+ sb->s_blocks_count_lo;
+ info.len = (u64)info.block_size * aux_info.len_blocks;
+
+ ext4_create_fs_aux_info();
+
+ memcpy(aux_info.sb, sb, sizeof(*sb));
+
+ if (aux_info.first_data_block != sb->s_first_data_block)
+ critical_error("first data block does not match");
+}
+
void ext4_create_resize_inode()
{
struct block_allocation *reserve_inode_alloc = create_allocation();
info.blocks_per_group;
u32 reserved_block_start = group_start_block + 1 +
aux_info.bg_desc_blocks;
- u32 reserved_block_len = aux_info.bg_desc_reserve_blocks;
+ u32 reserved_block_len = info.bg_desc_reserve_blocks;
append_region(reserve_inode_alloc, reserved_block_start,
reserved_block_len, i);
reserve_inode_len += reserved_block_len;
{
struct stat buf;
int ret;
+ u64 reserve_len = 0;
+ s64 computed_size;
ret = stat(filename, &buf);
if (ret)
return 0;
+ if (info.len < 0)
+ reserve_len = -info.len;
+
if (S_ISREG(buf.st_mode))
- return buf.st_size;
+ computed_size = buf.st_size - reserve_len;
else if (S_ISBLK(buf.st_mode))
- return get_block_device_size(filename);
+ computed_size = get_block_device_size(filename) - reserve_len;
else
- return 0;
+ computed_size = 0;
+
+ if (computed_size < 0) {
+ warn("Computed filesystem size less than 0");
+ computed_size = 0;
+ }
+
+ return computed_size;
}
u64 parse_num(const char *arg)
#ifndef _EXT4_UTILS_H_
#define _EXT4_UTILS_H_
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE
+#include <sys/types.h>
+#include <unistd.h>
+
#include <sys/types.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <setjmp.h>
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define ftruncate64 ftruncate
+#define mmap64 mmap
+#define off64_t off_t
+#endif
+
+#ifdef __BIONIC__
+extern void* __mmap2(void *, size_t, int, int, int, off_t);
+static inline void *mmap64(void *addr, size_t length, int prot, int flags,
+ int fd, off64_t offset)
+{
+ return __mmap2(addr, length, prot, flags, fd, offset >> 12);
+}
+#endif
extern int force;
#define warn(fmt, args...) do { fprintf(stderr, "warning: %s: " fmt "\n", __func__, ## args); } while (0)
-#define error(fmt, args...) do { fprintf(stderr, "error: %s: " fmt "\n", __func__, ## args); if (!force) exit(EXIT_FAILURE); } while (0)
-#define error_errno(s) error(s ": %s", strerror(errno))
-#define critical_error(fmt, args...) do { fprintf(stderr, "critical error: %s: " fmt "\n", __func__, ## args); exit(EXIT_FAILURE); } while (0)
-#define critical_error_errno(s) critical_error(s ": %s", strerror(errno))
+#define error(fmt, args...) do { fprintf(stderr, "error: %s: " fmt "\n", __func__, ## args); if (!force) longjmp(setjmp_env, EXIT_FAILURE); } while (0)
+#define error_errno(s, args...) error(s ": %s", ##args, strerror(errno))
+#define critical_error(fmt, args...) do { fprintf(stderr, "critical error: %s: " fmt "\n", __func__, ## args); longjmp(setjmp_env, EXIT_FAILURE); } while (0)
+#define critical_error_errno(s, args...) critical_error(s ": %s", ##args, strerror(errno))
#define EXT4_SUPER_MAGIC 0xEF53
#define EXT4_JNL_BACKUP_BLOCKS 1
#define __u8 u8
typedef unsigned long long u64;
+typedef signed long long s64;
typedef unsigned int u32;
typedef unsigned short int u16;
typedef unsigned char u8;
};
struct fs_info {
- u64 len;
+ s64 len; /* If set to 0, ask the block device for the size,
+ * if less than 0, reserve that much space at the
+ * end of the partition, else use the size given. */
u32 block_size;
u32 blocks_per_group;
u32 inodes_per_group;
u16 feat_ro_compat;
u16 feat_compat;
u16 feat_incompat;
+ u32 bg_desc_reserve_blocks;
const char *label;
u8 no_journal;
};
u32 inode_table_blocks;
u32 groups;
u32 bg_desc_blocks;
- u32 bg_desc_reserve_blocks;
u32 default_i_flags;
u32 blocks_per_ind;
u32 blocks_per_dind;
extern struct fs_info info;
extern struct fs_aux_info aux_info;
+extern jmp_buf setjmp_env;
+
static inline int log_2(int j)
{
int i;
}
int ext4_bg_has_super_block(int bg);
-void write_ext4_image(const char *filename, int gz, int sparse);
+void write_ext4_image(const char *filename, int gz, int sparse, int crc,
+ int wipe);
void ext4_create_fs_aux_info(void);
void ext4_free_fs_aux_info(void);
void ext4_fill_in_sb(void);
void ext4_create_resize_inode(void);
void ext4_create_journal_inode(void);
void ext4_update_free(void);
+void ext4_queue_sb(void);
u64 get_file_size(const char *filename);
u64 parse_num(const char *arg);
+void ext4_parse_sb(struct ext4_super_block *sb);
#endif
* limitations under the License.
*/
-#include <stdlib.h>
-#include <stdio.h>
-
#include "ext4_utils.h"
#include "ext4.h"
#include "ext4_extents.h"
#include "backed_block.h"
-
#include "extent.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+
/* Creates data buffers for the first backing_len bytes of a block allocation
and queues them to be written */
static u8 *extent_create_backing(struct block_allocation *alloc,
static void extent_create_backing_file(struct block_allocation *alloc,
u64 backing_len, const char *filename)
{
- off_t offset = 0;
+ off64_t offset = 0;
for (; alloc != NULL && backing_len > 0; get_next_region(alloc)) {
u32 region_block;
u32 region_len;
* limitations under the License.
*/
-#include <stdlib.h>
-#include <stdio.h>
-
#include "ext4_utils.h"
#include "ext4.h"
#include "ext4_extents.h"
#include "indirect.h"
#include "allocate.h"
+#include <stdlib.h>
+#include <stdio.h>
+
/* Creates data buffers for the first backing_len bytes of a block allocation
and queues them to be written */
static u8 *create_backing(struct block_allocation *alloc,
struct block_allocation *alloc)
{
u32 block_len = block_allocation_len(alloc);
- u32 superblocks = block_len / aux_info.bg_desc_reserve_blocks;
+ u32 superblocks = block_len / info.bg_desc_reserve_blocks;
u32 i, j;
u64 blocks;
u64 size;
- if (block_len % aux_info.bg_desc_reserve_blocks)
+ if (block_len % info.bg_desc_reserve_blocks)
critical_error("reserved blocks not a multiple of %d",
- aux_info.bg_desc_reserve_blocks);
+ info.bg_desc_reserve_blocks);
append_oob_allocation(alloc, 1);
u32 dind_block = get_oob_block(alloc, 0);
critical_error_errno("calloc");
queue_data_block((u8 *)dind_block_data, info.block_size, dind_block);
- u32 *ind_block_data = calloc(info.block_size, aux_info.bg_desc_reserve_blocks);
+ u32 *ind_block_data = calloc(info.block_size, info.bg_desc_reserve_blocks);
if (!ind_block_data)
critical_error_errno("calloc");
queue_data_block((u8 *)ind_block_data,
- info.block_size * aux_info.bg_desc_reserve_blocks,
+ info.block_size * info.bg_desc_reserve_blocks,
get_block(alloc, 0));
- for (i = 0; i < aux_info.bg_desc_reserve_blocks; i++) {
- int r = (i - aux_info.bg_desc_blocks) % aux_info.bg_desc_reserve_blocks;
+ for (i = 0; i < info.bg_desc_reserve_blocks; i++) {
+ int r = (i - aux_info.bg_desc_blocks) % info.bg_desc_reserve_blocks;
if (r < 0)
- r += aux_info.bg_desc_reserve_blocks;
+ r += info.bg_desc_reserve_blocks;
dind_block_data[i] = get_block(alloc, r);
for (j = 1; j < superblocks; j++) {
- u32 b = j * aux_info.bg_desc_reserve_blocks + r;
+ u32 b = j * info.bg_desc_reserve_blocks + r;
ind_block_data[r * aux_info.blocks_per_ind + j - 1] = get_block(alloc, b);
}
}
u32 last_block = EXT4_NDIR_BLOCKS + aux_info.blocks_per_ind +
- aux_info.blocks_per_ind * (aux_info.bg_desc_reserve_blocks - 1) +
+ aux_info.blocks_per_ind * (info.bg_desc_reserve_blocks - 1) +
superblocks - 2;
blocks = ((u64)block_len + 1) * info.block_size / 512;
* limitations under the License.
*/
-#define _GNU_SOURCE
+#include "make_ext4fs.h"
+#include "output_file.h"
+#include "ext4_utils.h"
+#include "allocate.h"
+#include "contents.h"
+#include "uuid.h"
+#include "backed_block.h"
#include <dirent.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include "make_ext4fs.h"
-#include "output_file.h"
-#include "ext4_utils.h"
-#include "allocate.h"
-#include "contents.h"
-#include "uuid.h"
-
#ifdef ANDROID
#include <private/android_filesystem_config.h>
#endif
return ALIGN(inodes, (info.block_size / info.inode_size));
}
+static u32 compute_bg_desc_reserve_blocks()
+{
+ u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
+ u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
+ u32 bg_desc_blocks = DIV_ROUND_UP(block_groups * sizeof(struct ext2_group_desc),
+ info.block_size);
+
+ u32 bg_desc_reserve_blocks =
+ DIV_ROUND_UP(block_groups * 1024 * sizeof(struct ext2_group_desc),
+ info.block_size) - bg_desc_blocks;
+
+ if (bg_desc_reserve_blocks > info.block_size / sizeof(u32))
+ bg_desc_reserve_blocks = info.block_size / sizeof(u32);
+
+ return bg_desc_reserve_blocks;
+}
+
void reset_ext4fs_info() {
// Reset all the global data structures used by make_ext4fs so it
// can be called again.
free_data_blocks();
}
-int make_ext4fs(const char *filename, const char *directory,
- char *mountpoint, int android, int gzip, int sparse)
+int make_ext4fs(const char *filename, s64 len)
+{
+ reset_ext4fs_info();
+ info.len = len;
+ return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0, 1);
+}
+
+int make_ext4fs_internal(const char *filename, const char *directory,
+ char *mountpoint, int android, int gzip, int sparse,
+ int crc, int wipe)
{
u32 root_inode_num;
u16 root_mode;
- if (info.len == 0)
+ if (setjmp(setjmp_env))
+ return EXIT_FAILURE; /* Handle a call to longjmp() */
+
+ if (info.len <= 0)
info.len = get_file_size(filename);
if (info.len <= 0) {
EXT4_FEATURE_INCOMPAT_FILETYPE;
+ info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks();
+
printf("Creating filesystem with parameters:\n");
printf(" Size: %llu\n", info.len);
printf(" Block size: %d\n", info.block_size);
printf(" Blocks: %llu\n", aux_info.len_blocks);
printf(" Block groups: %d\n", aux_info.groups);
- printf(" Reserved block group size: %d\n", aux_info.bg_desc_reserve_blocks);
+ printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
block_allocator_init();
ext4_update_free();
+ ext4_queue_sb();
+
printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
aux_info.sb->s_inodes_count,
aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
aux_info.sb->s_blocks_count_lo);
- write_ext4_image(filename, gzip, sparse);
+ write_ext4_image(filename, gzip, sparse, crc, wipe);
return 0;
}
#include "ext4.h"
void reset_ext4fs_info();
-int make_ext4fs(const char *filename, const char *directory,
- char *mountpoint, int android, int gzip, int sparse);
+int make_ext4fs(const char *filename, s64 len);
+int make_ext4fs_internal(const char *filename, const char *directory,
+ char *mountpoint, int android, int gzip, int sparse,
+ int crc, int wipe);
#endif
int android = 0;
int gzip = 0;
int sparse = 0;
+ int crc = 0;
+ int wipe = 0;
- while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fzJs")) != -1) {
+ while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsc")) != -1) {
switch (opt) {
case 'l':
info.len = parse_num(optarg);
android = 1;
mountpoint = optarg;
break;
+ case 'w':
+ wipe = 1;
+ break;
case 'z':
gzip = 1;
break;
case 'J':
info.no_journal = 1;
break;
+ case 'c':
+ crc = 1;
+ break;
case 's':
sparse = 1;
break;
exit(EXIT_FAILURE);
}
+ if (wipe && sparse) {
+ fprintf(stderr, "Cannot specifiy both wipe and sparse\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (wipe && gzip) {
+ fprintf(stderr, "Cannot specifiy both wipe and gzip\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
if (optind >= argc) {
fprintf(stderr, "Expected filename after options\n");
usage(argv[0]);
exit(EXIT_FAILURE);
}
- return make_ext4fs(filename, directory, mountpoint, android, gzip, sparse);
+ return make_ext4fs_internal(filename, directory, mountpoint, android, gzip,
+ sparse, crc, wipe);
}
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define _LARGEFILE64_SOURCE
+
+#include "ext4_utils.h"
+#include "output_file.h"
+#include "sparse_format.h"
+#include "sparse_crc32.h"
+#include "wipe.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <zlib.h>
-#include "ext4_utils.h"
-#include "output_file.h"
-#include "sparse_format.h"
-#include "sparse_crc32.h"
-
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#define off64_t off_t
gzFile gz_fd;
int sparse;
u64 cur_out_ptr;
- int chunk_cnt;
+ u32 chunk_cnt;
u32 crc32;
struct output_file_ops *ops;
+ int use_crc;
};
static int file_seek(struct output_file *out, off64_t off)
out->cur_out_ptr += skip_len;
out->chunk_cnt++;
- /* Compute the CRC for all those zeroes. Do it block_size bytes at a time. */
- while (skip_len) {
- chunk = (skip_len > info.block_size) ? info.block_size : skip_len;
- out->crc32 = sparse_crc32(out->crc32, zero_buf, chunk);
- skip_len -= chunk;
- }
-
return 0;
}
return -1;
}
- out->crc32 = sparse_crc32(out->crc32, data, len);
- if (zero_len)
- out->crc32 = sparse_crc32(out->crc32, zero_buf, zero_len);
+ if (out->use_crc) {
+ out->crc32 = sparse_crc32(out->crc32, data, len);
+ if (zero_len)
+ out->crc32 = sparse_crc32(out->crc32, zero_buf, zero_len);
+ }
+
out->cur_out_ptr += rnd_up_len;
out->chunk_cnt++;
void close_output_file(struct output_file *out)
{
int ret;
+ chunk_header_t chunk_header;
if (out->sparse) {
- /* we need to seek back to the beginning and update the file header */
- sparse_header.total_chunks = out->chunk_cnt;
- sparse_header.image_checksum = out->crc32;
+ if (out->use_crc) {
+ chunk_header.chunk_type = CHUNK_TYPE_CRC32;
+ chunk_header.reserved1 = 0;
+ chunk_header.chunk_sz = 0;
+ chunk_header.total_sz = CHUNK_HEADER_LEN + 4;
- ret = out->ops->seek(out, 0);
- if (ret < 0)
- error("failure seeking to start of sparse file");
+ out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header));
+ out->ops->write(out, (u8 *)&out->crc32, 4);
- ret = out->ops->write(out, (u8 *)&sparse_header, sizeof(sparse_header));
- if (ret < 0)
- error("failure updating sparse file header");
+ out->chunk_cnt++;
+ }
+
+ if (out->chunk_cnt != sparse_header.total_chunks)
+ error("sparse chunk count did not match: %d %d", out->chunk_cnt,
+ sparse_header.total_chunks);
}
out->ops->close(out);
}
-struct output_file *open_output_file(const char *filename, int gz, int sparse)
+struct output_file *open_output_file(const char *filename, int gz, int sparse,
+ int chunks, int crc, int wipe)
{
int ret;
struct output_file *out = malloc(sizeof(struct output_file));
return NULL;
}
} else {
- out->ops = &file_ops;
- out->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (out->fd < 0) {
- error_errno("open");
- free(out);
- return NULL;
+ if (strcmp(filename, "-")) {
+ out->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (out->fd < 0) {
+ error_errno("open");
+ free(out);
+ return NULL;
+ }
+ } else {
+ out->fd = STDOUT_FILENO;
}
+ out->ops = &file_ops;
}
out->sparse = sparse;
out->cur_out_ptr = 0ll;
/* Initialize the crc32 value */
out->crc32 = 0;
+ out->use_crc = crc;
+
+ if (wipe)
+ wipe_block_device(out->fd, info.len);
if (out->sparse) {
- /* Write out the file header. We'll update the unknown fields
- * when we close the file.
- */
sparse_header.blk_sz = info.block_size,
sparse_header.total_blks = info.len / info.block_size,
+ sparse_header.total_chunks = chunks;
+ if (out->use_crc)
+ sparse_header.total_chunks++;
+
ret = out->ops->write(out, (u8 *)&sparse_header, sizeof(sparse_header));
if (ret < 0)
return NULL;
{
int ret;
- if (len > info.len) {
+ if (len > (u64) info.len) {
error("attempted to pad file %llu bytes past end of filesystem",
len - info.len);
return;
if (out->sparse) {
/* We need to emit a DONT_CARE chunk to pad out the file if the
* cur_out_ptr is not already at the end of the filesystem.
- * We also need to compute the CRC for it.
*/
if (len < out->cur_out_ptr) {
error("attempted to pad file %llu bytes less than the current output pointer",
{
int ret;
- if (off + len > info.len) {
+ if (off + len > (u64) info.len) {
error("attempted to write block %llu past end of filesystem",
off + len - info.len);
return;
/* Write a contiguous region of data blocks from a file */
void write_data_file(struct output_file *out, u64 off, const char *file,
- off_t offset, int len)
+ off64_t offset, int len)
{
int ret;
+ off64_t aligned_offset;
+ int aligned_diff;
- if (off + len >= info.len) {
+ if (off + len >= (u64) info.len) {
error("attempted to write block %llu past end of filesystem",
off + len - info.len);
return;
return;
}
- u8 *data = mmap(NULL, len, PROT_READ, MAP_SHARED, file_fd, offset);
+ aligned_offset = offset & ~(4096 - 1);
+ aligned_diff = offset - aligned_offset;
+
+ u8 *data = mmap64(NULL, len + aligned_diff, PROT_READ, MAP_SHARED, file_fd,
+ aligned_offset);
if (data == MAP_FAILED) {
- error_errno("mmap");
+ error_errno("mmap64");
close(file_fd);
return;
}
if (out->sparse) {
- write_chunk_raw(out, off, data, len);
+ write_chunk_raw(out, off, data + aligned_diff, len);
} else {
ret = out->ops->seek(out, off);
if (ret < 0)
goto err;
- ret = out->ops->write(out, data, len);
+ ret = out->ops->write(out, data + aligned_diff, len);
if (ret < 0)
goto err;
}
munmap(data, len);
close(file_fd);
}
-
* limitations under the License.
*/
+#ifndef _OUTPUT_FILE_H_
+#define _OUTPUT_FILE_H_
+
struct output_file;
-struct output_file *open_output_file(const char *filename, int gz, int sparse);
+struct output_file *open_output_file(const char *filename, int gz, int sparse,
+ int chunks, int crc, int wipe);
void write_data_block(struct output_file *out, u64 off, u8 *data, int len);
void write_data_file(struct output_file *out, u64 off, const char *file,
- off_t offset, int len);
+ off64_t offset, int len);
void pad_output_file(struct output_file *out, u64 len);
void close_output_file(struct output_file *out);
+
+#endif
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
+
+#include "ext4_utils.h"
+#include "sparse_format.h"
+#include "sparse_crc32.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
-#include "ext4_utils.h"
-#include "output_file.h"
-#include "sparse_format.h"
-#include "sparse_crc32.h"
-
-#if defined(__APPLE__) && defined(__MACH__)
-#define lseek64 lseek
-#define off64_t off_t
-#endif
-
#define COPY_BUF_SIZE (1024*1024)
u8 *copybuf;
fprintf(stderr, "Usage: simg2img <sparse_image_file> <raw_image_file>\n");
}
-int process_raw_chunk(FILE *in, FILE *out, u32 blocks, u32 blk_sz, u32 *crc32)
+static int read_all(int fd, void *buf, size_t len)
+{
+ size_t total = 0;
+ int ret;
+ char *ptr = buf;
+
+ while (total < len) {
+ ret = read(fd, ptr, len - total);
+
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0)
+ return total;
+
+ ptr += ret;
+ total += ret;
+ }
+
+ return total;
+}
+
+static int write_all(int fd, void *buf, size_t len)
+{
+ size_t total = 0;
+ int ret;
+ char *ptr = buf;
+
+ while (total < len) {
+ ret = write(fd, ptr, len - total);
+
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0)
+ return total;
+
+ ptr += ret;
+ total += ret;
+ }
+
+ return total;
+}
+
+int process_raw_chunk(int in, int out, u32 blocks, u32 blk_sz, u32 *crc32)
{
u64 len = (u64)blocks * blk_sz;
+ int ret;
int chunk;
while (len) {
chunk = (len > COPY_BUF_SIZE) ? COPY_BUF_SIZE : len;
- if (fread(copybuf, chunk, 1, in) != 1) {
- fprintf(stderr, "fread returned an error copying a raw chunk\n");
+ ret = read_all(in, copybuf, chunk);
+ if (ret != chunk) {
+ fprintf(stderr, "read returned an error copying a raw chunk: %d %d\n",
+ ret, chunk);
exit(-1);
}
*crc32 = sparse_crc32(*crc32, copybuf, chunk);
- if (fwrite(copybuf, chunk, 1, out) != 1) {
- fprintf(stderr, "fwrite returned an error copying a raw chunk\n");
+ ret = write_all(out, copybuf, chunk);
+ if (ret != chunk) {
+ fprintf(stderr, "write returned an error copying a raw chunk\n");
exit(-1);
}
len -= chunk;
}
-int process_skip_chunk(FILE *out, u32 blocks, u32 blk_sz, u32 *crc32)
+int process_skip_chunk(int out, u32 blocks, u32 blk_sz, u32 *crc32)
{
/* len needs to be 64 bits, as the sparse file specifies the skip amount
* as a 32 bit value of blocks.
*/
u64 len = (u64)blocks * blk_sz;
- u64 len_save;
- u32 skip_chunk;
- /* Fseek takes the offset as a long, which may be 32 bits on some systems.
- * So, lets do a sequence of fseeks() with SEEK_CUR to get the file pointer
- * where we want it.
- */
- len_save = len;
- while (len) {
- skip_chunk = (len > 0x80000000) ? 0x80000000 : len;
- fseek(out, skip_chunk, SEEK_CUR);
- len -= skip_chunk;
+ lseek64(out, len, SEEK_CUR);
+
+ return blocks;
+}
+
+int process_crc32_chunk(int in, u32 crc32)
+{
+ u32 file_crc32;
+ int ret;
+
+ ret = read_all(in, &file_crc32, 4);
+ if (ret != 4) {
+ fprintf(stderr, "read returned an error copying a crc32 chunk\n");
+ exit(-1);
}
- /* And compute the CRC of the skipped region a chunk at a time */
- len = len_save;
- while (len) {
- skip_chunk = (skip_chunk > blk_sz) ? blk_sz : skip_chunk;
- *crc32 = sparse_crc32(*crc32, zerobuf, skip_chunk);
- len -= skip_chunk;
+
+ if (file_crc32 != crc32) {
+ fprintf(stderr, "computed crc32 of 0x%8.8x, expected 0x%8.8x\n",
+ crc32, file_crc32);
+ exit(-1);
}
- return blocks;
+ return 0;
}
int main(int argc, char *argv[])
{
- FILE *in, *out;
+ int in;
+ int out;
unsigned int i;
sparse_header_t sparse_header;
chunk_header_t chunk_header;
u32 crc32 = 0;
u32 total_blocks = 0;
+ int ret;
if (argc != 3) {
usage();
exit(-1);
}
- if ((in = fopen(argv[1], "rb")) == 0) {
- fprintf(stderr, "Cannot open input file %s\n", argv[1]);
- exit(-1);
+ if (strcmp(argv[1], "-") == 0) {
+ in = STDIN_FILENO;
+ } else {
+ if ((in = open(argv[1], O_RDONLY)) == 0) {
+ fprintf(stderr, "Cannot open input file %s\n", argv[1]);
+ exit(-1);
+ }
}
- if ((out = fopen(argv[2], "wb")) == 0) {
- fprintf(stderr, "Cannot open output file %s\n", argv[2]);
- exit(-1);
+ if (strcmp(argv[2], "-") == 0) {
+ out = STDOUT_FILENO;
+ } else {
+ if ((out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666)) == 0) {
+ fprintf(stderr, "Cannot open output file %s\n", argv[2]);
+ exit(-1);
+ }
}
- if (fread(&sparse_header, sizeof(sparse_header), 1, in) != 1) {
+ ret = read_all(in, &sparse_header, sizeof(sparse_header));
+ if (ret != sizeof(sparse_header)) {
fprintf(stderr, "Error reading sparse file header\n");
exit(-1);
}
/* Skip the remaining bytes in a header that is longer than
* we expected.
*/
- fseek(in, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR);
+ lseek64(in, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR);
}
if ( (zerobuf = malloc(sparse_header.blk_sz)) == 0) {
}
for (i=0; i<sparse_header.total_chunks; i++) {
- if (fread(&chunk_header, sizeof(chunk_header), 1, in) != 1) {
+ ret = read_all(in, &chunk_header, sizeof(chunk_header));
+ if (ret != sizeof(chunk_header)) {
fprintf(stderr, "Error reading chunk header\n");
exit(-1);
}
/* Skip the remaining bytes in a header that is longer than
* we expected.
*/
- fseek(in, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR);
+ lseek64(in, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR);
}
switch (chunk_header.chunk_type) {
total_blocks += process_skip_chunk(out,
chunk_header.chunk_sz, sparse_header.blk_sz, &crc32);
break;
+ case CHUNK_TYPE_CRC32:
+ process_crc32_chunk(in, crc32);
+ break;
default:
fprintf(stderr, "Unknown chunk type 0x%4.4x\n", chunk_header.chunk_type);
- exit(-1);
}
}
* will make the file the correct size. Make sure the offset is
* computed in 64 bits, and the function called can handle 64 bits.
*/
- if (ftruncate(fileno(out), (u64)total_blocks * sparse_header.blk_sz)) {
+ if (ftruncate64(out, (u64)total_blocks * sparse_header.blk_sz)) {
fprintf(stderr, "Error calling ftruncate() to set the image size\n");
exit(-1);
}
- fclose(in);
- fclose(out);
+ close(in);
+ close(out);
if (sparse_header.total_blks != total_blocks) {
fprintf(stderr, "Wrote %d blocks, expected to write %d blocks\n",
exit(-1);
}
- if (sparse_header.image_checksum != crc32) {
- fprintf(stderr, "computed crc32 of 0x%8.8x, expected 0x%8.8x\n",
- crc32, sparse_header.image_checksum);
- exit(-1);
- }
-
exit(0);
}
#define CHUNK_TYPE_RAW 0xCAC1
#define CHUNK_TYPE_FILL 0xCAC2
#define CHUNK_TYPE_DONT_CARE 0xCAC3
+#define CHUNK_TYPE_CRC32 0xCAC4
typedef struct chunk_header {
__le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
__le32 total_sz; /* in bytes of chunk input file including chunk header and data */
} chunk_header_t;
-/* Following a Raw or Fill chunk is data. For a Raw chunk, it's the data in chunk_sz * blk_sz.
+/* Following a Raw or Fill or CRC32 chunk is data.
+ * For a Raw chunk, it's the data in chunk_sz * blk_sz.
* For a Fill chunk, it's 4 bytes of the fill data.
+ * For a CRC32 chunk, it's 4 bytes of CRC32
*/
--- /dev/null
+/*
+ * Copyright (C) 2011 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 "ext4_utils.h"
+#include "wipe.h"
+
+#if defined(__linux__)
+
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+
+#ifndef BLKDISCARD
+#define BLKDISCARD _IO(0x12,119)
+#endif
+
+#ifndef BLKSECDISCARD
+#define BLKSECDISCARD _IO(0x12,125)
+#endif
+
+int wipe_block_device(int fd, s64 len)
+{
+ u64 range[2];
+ int ret;
+
+ range[0] = 0;
+ range[1] = len;
+ ret = ioctl(fd, BLKSECDISCARD, &range);
+ if (ret < 0) {
+ range[0] = 0;
+ range[1] = len;
+ ret = ioctl(fd, BLKDISCARD, &range);
+ if (ret < 0) {
+ warn("Discard failed\n");
+ return 1;
+ } else {
+ warn("Wipe via secure discard failed, used discard instead\n");
+ return 0;
+ }
+ }
+
+ return 0;
+}
+#else
+int wipe_block_device(int fd, s64 len)
+{
+ error("wipe not supported on non-linux platforms");
+ return 1;
+}
+#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _WIPE_H_
+#define _WIPE_H_
+
+int wipe_block_device(int fd, s64 len);
+
+#endif
#include <assert.h>
#include <string.h>
-#include <sys/endian.h>
+#include <endian.h>
#include "fat.h"
#include <assert.h>
#include <string.h>
-#include <sys/endian.h>
+#include <endian.h>
#include "fatblock.h"
#include "fat.h"
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := ublock.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_PRELINK_MODULE := false
+
include $(BUILD_SHARED_LIBRARY)
-ifeq ($(TARGET_ARCH),arm)
include $(call all-subdir-makefiles)
-endif
int cpu_;
};
-// Workaround for missing sched_setaffinity(2) and getcpu(2)
-#ifndef CPU_SETSIZE
-#define HAVE_CUSTOM_CPU_SETSIZE 1
-#define CPU_SETSIZE 1024
-struct getcpu_cache;
-typedef struct { uint64_t bits[CPU_SETSIZE / 64]; } cpu_set_t;
-static int sched_getaffinity(pid_t pid, unsigned int cpusetsize,
- cpu_set_t *set);
-static int sched_setaffinity(pid_t pid, unsigned int cpusetsize,
- cpu_set_t *mask);
-//static int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
-static int sched_getcpu(void);
-static int CPU_ISSET(int cpu, const cpu_set_t *set);
-static void CPU_SET(int cpu, cpu_set_t *set);
-static void CPU_ZERO(cpu_set_t *set);
-#endif /* !CPU_SETSIZE */
-
// File scope function prototypes
static void server(void);
static void client(void);
cerr << "expected: " << expected << endl;
}
- if (options.iterDelay > 0.0) { testDelay(options.iterDelay); }
+ if (options.iterDelay > 0.0) { testDelaySpin(options.iterDelay); }
}
// Display the results
return stream;
}
-
-#ifdef HAVE_CUSTOM_CPU_SETSIZE
-// ======== Local implementation of system calls with missing bionic call stubs
-static int sched_getaffinity(pid_t pid, unsigned int cpusetsize,
- cpu_set_t *set)
-{
- int rv;
-
- rv = syscall(__NR_sched_getaffinity, pid, cpusetsize, set);
- if (rv < 0) { return rv; }
-
- // Kernel implementation of sched_getaffinity() returns the number
- // of bytes in the set that it set. Set the rest of our set bits
- // to 0.
- memset(((char *) set) + rv, 0x00, sizeof(cpu_set_t) - rv);
-
- return 0;
-}
-
-static int sched_setaffinity(pid_t pid, unsigned int cpusetsize,
- cpu_set_t *mask)
-{
- int rv;
-
- rv = syscall(__NR_sched_setaffinity, pid, cpusetsize, mask);
-
- return rv;
-}
-
-static int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
-{
- int rv;
-
- rv = syscall(345, cpu, node, tcache);
-
- return rv;
-}
-
-static int sched_getcpu(void)
-{
- unsigned cpu;
- int ret = getcpu(&cpu, NULL, NULL);
- if (ret == 0)
- ret = (int)cpu;
-}
-
-static int CPU_ISSET(int cpu, const cpu_set_t *set)
-{
- if (cpu < 0) { return 0; }
- if ((unsigned) cpu >= (sizeof(cpu_set_t) * CHAR_BIT)) { return 0; }
-
- if ((*((uint64_t *)set + (cpu / 64))) & (1ULL << (cpu % 64))) {
- return true;
- }
-
- return false;
-}
-
-static void CPU_SET(int cpu, cpu_set_t *set)
-{
- if (cpu < 0) { return; }
- if ((unsigned) cpu > (sizeof(cpu_set_t) * CHAR_BIT)) { return; }
-
- *((uint64_t *)set + (cpu / 64)) |= 1ULL << (cpu % 64);
-}
-
-static void CPU_ZERO(cpu_set_t *set)
-{
- memset(set, 0x00, sizeof(cpu_set_t));
-}
-#endif /* HAVE_CUSTOM_CPU_SETSIZE */
# First, the tests in 'common'
sources := \
+ common/test_clock.c \
common/test_cpu_set.c \
common/test_drand48.c \
common/test_executable_destructor.c \
common/test_seteuid.c \
common/test_static_cpp_mutex.cpp \
common/test_strftime_2039.c \
+ common/test_strptime.c \
common/test_tm_zone.c \
common/test_udp.c \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := bionic/lib_relocs.c
LOCAL_MODULE := libtest_relocs
-LOCAL_PRELINK_MODULE := false
+
LOCAL_MODULE_TAGS := tests
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := bionic/lib_static_init.cpp
LOCAL_MODULE := libtest_static_init
-LOCAL_PRELINK_MODULE := false
+
LOCAL_MODULE_TAGS := tests
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := bionic/libdlclosetest1.cpp
LOCAL_MODULE := libdlclosetest1
-LOCAL_PRELINK_MODULE := false
+
LOCAL_MODULE_TAGS := tests
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := bionic/libdlclosetest2.c
LOCAL_MODULE := libdlclosetest2
-LOCAL_PRELINK_MODULE := false
+
LOCAL_MODULE_TAGS := tests
include $(BUILD_SHARED_LIBRARY)
}
fprintf(stderr, "%s unloaded.\n", libname);
+ if (y != 2) {
+ fprintf(stderr, "Static destructors was not called on dlclose()!\n");
+ return 2;
+ }
return 0;
}
--- /dev/null
+/*
+ * Copyright (C) 2011 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.
+ */
+
+// Minimal test program for clock
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+// this thread soaks the CPU so that clock() function will advance
+void *cpu_hog(void *arg)
+{
+ for (;;) {
+ // the system call should not be optimized away by the compiler
+ (void) getpid();
+ }
+}
+
+int main(int argc, char **argv)
+{
+ pthread_t thread;
+ clock_t ticks10, ticks15;
+
+ // do not call clock() here so we can test initialization
+
+ // soak the CPU for 10 seconds, then read clock
+ pthread_create(&thread, NULL, cpu_hog, NULL);
+ sleep(10);
+ ticks10 = clock();
+
+ // soak the CPU for 5 more seconds, then read clock
+ sleep(5);
+ ticks15 = clock();
+
+ // print the results
+ printf("CLOCKS_PER_SEC = %ld ticks/sec\n", (clock_t) CLOCKS_PER_SEC);
+ printf("At 10 secs clock=%lu, at 15 secs clock=%lu\n", ticks10, ticks15);
+
+ // exit could wait for the other thread to complete
+ _exit(EXIT_SUCCESS);
+}
--- /dev/null
+/*
+ * Copyright (C) 2011 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.
+ */
+
+// Minimal test program for strptime
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int main(int argc, char **argv)
+{
+ struct tm tm;
+ char buf[255];
+
+ // For now, only test a couple of formats that use recursion
+
+ memset(&tm, 0, sizeof(tm));
+ strptime("11:14", "%R", &tm);
+ strftime(buf, sizeof(buf), "%H:%M", &tm);
+ puts(buf);
+ puts(!strcmp(buf, "11:14") ? "OK" : "FAILED");
+
+ memset(&tm, 0, sizeof(tm));
+ strptime("09:41:53", "%T", &tm);
+ strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
+ puts(buf);
+ puts(!strcmp(buf, "09:41:53") ? "OK" : "FAILED");
+
+ return EXIT_SUCCESS;
+}
DEVICE_TEST_DIR=/data/local/bionic-test
DEVICE_TEST=$DEVICE_TEST_DIR/$TESTNAME
-adb_cmd mkdir -p $DEVICE_TEST_DIR
+adb_cmd mkdir $DEVICE_TEST_DIR
$ADB_CMD push $TESTEXE $DEVICE_TEST_DIR/
if [ $? != 0 ] ; then
echo "ERROR: Can't push test to device!"
#include <linux/fb.h>
#include <linux/kd.h>
-#include <pixelflinger/pixelflinger.h>
-
-#include "minui.h"
-
-typedef struct {
- GGLSurface texture;
- unsigned cwidth;
- unsigned cheight;
- unsigned ascent;
-} GRFont;
-
-static GGLContext *gr_context = 0;
-static GGLSurface gr_framebuffer[2];
+struct simple_fb {
+ void *data;
+ int width;
+ int height;
+ int stride;
+ int bpp;
+};
+
+static struct simple_fb gr_fbs[2];
static unsigned gr_active_fb = 0;
static int gr_fb_fd = -1;
static void dumpinfo(struct fb_fix_screeninfo *fi,
struct fb_var_screeninfo *vi);
-static int get_framebuffer(GGLSurface *fb)
+static int get_framebuffer(struct simple_fb *fb, unsigned bpp)
{
int fd;
void *bits;
+ int bytes_per_pixel;
fd = open("/dev/graphics/fb0", O_RDWR);
if (fd < 0) {
}
}
- if(ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
+ if(ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
perror("failed to get fb0 info");
return -1;
}
- if(ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
+ if (bpp && vi.bits_per_pixel != bpp) {
+ printf("bpp != %d, forcing...\n", bpp);
+ vi.bits_per_pixel = bpp;
+ if(ioctl(fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
+ perror("failed to force bpp");
+ return -1;
+ }
+ }
+
+ if(ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
perror("failed to get fb0 info");
return -1;
}
return -1;
}
- fb->version = sizeof(*fb);
+ bytes_per_pixel = vi.bits_per_pixel >> 3;
+
fb->width = vi.xres;
fb->height = vi.yres;
- fb->stride = fi.line_length / (vi.bits_per_pixel >> 3);
+ fb->stride = fi.line_length / bytes_per_pixel;
fb->data = bits;
- fb->format = GGL_PIXEL_FORMAT_RGB_565;
+ fb->bpp = vi.bits_per_pixel;
fb++;
- fb->version = sizeof(*fb);
fb->width = vi.xres;
fb->height = vi.yres;
- fb->stride = fi.line_length / (vi.bits_per_pixel >> 3);
- fb->data = (void*) (((unsigned) bits) + vi.yres * vi.xres * 2);
- fb->format = GGL_PIXEL_FORMAT_RGB_565;
+ fb->stride = fi.line_length / bytes_per_pixel;
+ fb->data = (void *)((unsigned long)bits +
+ vi.yres * vi.xres * bytes_per_pixel);
+ fb->bpp = vi.bits_per_pixel;
return fd;
}
}
-int gr_init(void)
+int gr_init(int bpp, int id)
{
int fd = -1;
}
}
- gr_fb_fd = get_framebuffer(gr_framebuffer);
+ gr_fb_fd = get_framebuffer(gr_fbs, bpp);
if(gr_fb_fd < 0) {
if (fd >= 0) {
gr_vt_fd = fd;
/* start with 0 as front (displayed) and 1 as back (drawing) */
- gr_active_fb = 0;
- set_active_framebuffer(0);
+ gr_active_fb = id;
+ set_active_framebuffer(id);
return 0;
}
int gr_fb_width(void)
{
- return gr_framebuffer[0].width;
+ return gr_fbs[0].width;
}
int gr_fb_height(void)
{
- return gr_framebuffer[0].height;
+ return gr_fbs[0].height;
}
uint16_t red = 0xf800;
uint16_t green = 0x07e0;
uint16_t blue = 0x001f;
+uint16_t white = 0xffff;
+uint16_t black = 0x0;
+
+uint32_t red32 = 0x00ff0000;
+uint32_t green32 = 0x0000ff00;
+uint32_t blue32 = 0x000000ff;
+uint32_t white32 = 0x00ffffff;
+uint32_t black32 = 0x0;
+
+void draw_grid(int w, int h, void* _loc) {
+ int i, j;
+ int v;
+ int stride = fi.line_length / (vi.bits_per_pixel >> 3);
+ uint16_t *loc = _loc;
+ uint32_t *loc32 = _loc;
+
+ for (j = 0; j < h/2; j++) {
+ for (i = 0; i < w/2; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = red;
+ else
+ loc32[i + j*(stride)] = red32;
+ for (; i < w; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = green;
+ else
+ loc32[i + j*(stride)] = green32;
+ }
-void draw_grid(int w, int h, uint16_t* loc) {
- int i, j;
- int v;
- int stride = fi.line_length / (vi.bits_per_pixel >> 3);
-
- for (j = 0; j < h/2; j++) {
- for (i = 0; i < w/2; i++)
- loc[i + j*(stride)] = red;
- for (; i < w; i++)
- loc[i + j*(stride)] = green;
- }
- for (; j < h; j++) {
- for (i = 0; i < w/2; i++)
- loc[i + j*(stride)] = blue;
- for (; i < w; i++)
- loc[i + j*(stride)] = 0xffff;
- }
+ for (; j < h; j++) {
+ for (i = 0; i < w/2; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = blue;
+ else
+ loc32[i + j*(stride)] = blue32;
+ for (; i < w; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = white;
+ else
+ loc32[i + j*(stride)] = white32;
+ }
}
-void clear_screen(int w, int h, uint16_t* loc)
+void clear_screen(int w, int h, void* _loc)
{
int i,j;
int stride = fi.line_length / (vi.bits_per_pixel >> 3);
-
- for (j = 0; j < h; j++)
- for (i = 0; i < w; i++)
- loc[i + j*(stride)] = 0x0000;
+ uint16_t *loc = _loc;
+ uint32_t *loc32 = _loc;
+
+ for (j = 0; j < h; j++)
+ for (i = 0; i < w; i++)
+ if (vi.bits_per_pixel == 16)
+ loc[i + j*(stride)] = black;
+ else
+ loc32[i + j*(stride)] = black32;
}
int main(int argc, char **argv) {
int w;
int h;
int id = 0;
- gr_init();
- w = vi.xres;
- h = vi.yres;
- clear_screen(w, h, (uint16_t *)gr_framebuffer[0].data);
- clear_screen(w, h, (uint16_t *)gr_framebuffer[1].data);
-
- if (argc > 2) {
- w = atoi(argv[1]);
- h = atoi(argv[2]);
+ int bpp = 0;
+
+ if (argc > 1)
+ bpp = atoi(argv[1]);
+
+ if (argc > 4)
+ id = !!atoi(argv[4]);
+
+ gr_init(bpp, id);
+
+ if (argc > 3) {
+ w = atoi(argv[2]);
+ h = atoi(argv[3]);
+ } else {
+ w = vi.xres;
+ h = vi.yres;
}
- if (argc > 3)
- id = !!atoi(argv[3]);
+ clear_screen(vi.xres, vi.yres, gr_fbs[0].data);
+ clear_screen(vi.xres, vi.yres, gr_fbs[1].data);
+
+ draw_grid(w, h, gr_fbs[id].data);
- draw_grid(w, h, (uint16_t *)gr_framebuffer[id].data);
set_active_framebuffer(!id);
set_active_framebuffer(id);
# Copyright 2006 The Android Open Source Project
-
+ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
+endif
const struct timeval *second);
void testDelay(float amt);
+void testDelaySpin(float amt);
// Pseudo Random Utilities
int testRandBool(void);
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include
LOCAL_CFLAGS += -std=c99
LOCAL_SHARED_LIBRARIES += libcutils libutils
-LOCAL_PRELINK_MODULE := false
+
include $(BUILD_STATIC_LIBRARY)
} while (true);
}
+// Delay spins for the number of seconds specified by amt or a greater
+// amount. The amt variable is of type float and thus non-integer amounts
+// of time can be specified. Differs from testDelay() in that
+// testDelaySpin() performs a spin loop, instead of using nanosleep().
+void testDelaySpin(float amt)
+{
+ struct timespec start, current, delta;
+
+ // Get the time at which we started
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ do {
+ // Get current time
+ clock_gettime(CLOCK_MONOTONIC, ¤t);
+
+ // How much time is left
+ delta = tsDelta(&start, ¤t);
+ if (ts2double(&delta) > amt) { break; }
+ } while (true);
+}
+
/*
* Hex Dump
*
# Copyright 2006 The Android Open Source Project
-
+ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -fomit-frame-pointer
include $(BUILD_EXECUTABLE)
+endif
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := wifiLoadScanAssoc_test
+LOCAL_MODULE := wifiLoadScanAssoc
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativestresstest
-LOCAL_SRC_FILES := wifiLoadScanAssoc_test.c
+LOCAL_SRC_FILES := wifiLoadScanAssoc.c
LOCAL_SHARED_LIBRARIES += libcutils libutils libhardware_legacy
LOCAL_STATIC_LIBRARIES += libtestUtil
LOCAL_C_INCLUDES += system/extras/tests/include \
// File scope prototypes
static void init(void);
-static void execCmd(const char *cmd);
static void randDelay(void);
static void randBind(const cpu_set_t *availSet, int *chosenCPU);
testPrintE("Command too long for: %s\n", CMD_STATUS);
exit(22);
}
- execCmd(cmd);
+ testExecCmd(cmd);
}
// Stop Supplicant
testPrintE("Command too long for: %s\n", CMD_STATUS);
exit(22);
}
- execCmd(cmd);
+ testExecCmd(cmd);
}
// Start framework
testPrintE("Command too long for: %s\n", CMD_START_FRAMEWORK);
exit(27);
}
- execCmd(cmd);
+ testExecCmd(cmd);
testPrintI("Successfully completed %u passes", pass - startPass);
testPrintE("Command too long for: %s\n", CMD_STOP_FRAMEWORK);
exit(41);
}
- execCmd(cmd);
+ testExecCmd(cmd);
// Is WiFi driver loaded?
// If so stop the wpa_supplicant and unload the driver.
}
/*
- * Execute Command
- *
- * Executes the command pointed to by cmd. Which CPU executes the
- * command is randomly selected from the set of CPUs that were
- * available during testcase initialization. Output from the
- * executed command is captured and sent to LogCat Info. Once
- * the command has finished execution, it's exit status is captured
- * and checked for an exit status of zero. Any other exit status
- * causes diagnostic information to be printed and an immediate
- * testcase failure.
- */
-void
-execCmd(const char *cmd)
-{
- FILE *fp;
- int rv;
- int status;
- char str[MAXSTR];
- int cpu;
-
- // Randomly bind to one of the available CPUs
- randBind(&availCPU, &cpu);
-
- // Display CPU executing on and command to be executed
- testPrintI("CPU: %u cmd: %s", cpu, cmd);
-
- // Execute the command
- fflush(stdout);
- if ((fp = popen(cmd, "r")) == NULL) {
- testPrintE("execCmd popen failed, errno: %i", errno);
- exit(61);
- }
-
- // Obtain and display each line of output from the executed command
- while (fgets(str, sizeof(str), fp) != NULL) {
- if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
- str[strlen(str) - 1] = '\0';
- }
- testPrintI(" out: %s", str);
- testDelay(0.1);
- }
-
- // Obtain and check return status of executed command.
- // Fail on non-zero exit status
- status = pclose(fp);
- if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
- testPrintE("Unexpected command failure");
- testPrintE(" status: %#x", status);
- if (WIFEXITED(status)) {
- testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
- }
- if (WIFSIGNALED(status)) {
- testPrintE("WTERMSIG: %i", WTERMSIG(status));
- }
- exit(62);
- }
-}
-
-/*
* Random Delay
*
* Delays for a random amount of time within the range given
{
const unsigned long nanosecspersec = 1000000000;
float fract, biasedFract, amt;
- struct timespec remaining;
- struct timeval start, current, delta;
+ struct timeval startTime, endTime;
// Obtain start time
- gettimeofday(&start, NULL);
+ gettimeofday(&startTime, NULL);
// Determine random amount to sleep.
// Values closer to delayMin are prefered by an amount
biasedFract = pow(DELAY_EXP, fract) / pow(DELAY_EXP, 1.0);
amt = delayMin + ((delayMax - delayMin) * biasedFract);
- do {
- // Get current time
- gettimeofday(¤t, NULL);
-
- // How much time is left
- delta = tvDelta(&start, ¤t);
- if (tv2double(&delta) > amt) { break; }
-
- // Request to sleep for the remaining time
- remaining = double2ts(amt - tv2double(&delta));
- (void) nanosleep(&remaining, NULL);
- } while (true);
+ // Delay
+ testDelay(amt);
+ // Obtain end time and display delta
+ gettimeofday(&endTime, NULL);
testPrintI("delay: %.2f",
- (float) (tv2double(¤t) - tv2double(&start)));
+ (float) (tv2double(&endTime) - tv2double(&startTime)));
}
static void