Skip to content

Commit

Permalink
Merge changes from topic "ext2simg-fixes"
Browse files Browse the repository at this point in the history
* changes:
  ext2simg: fix same_file() with symlinks
  ext2simg: fix error check of io_channel_read_blk64()
  ext2simg: clean up integer types and check for too-large fs
  ext2simg: clean up add_chunk()
  ext2simg: use a standard flexible array
  ext2simg: use bool where appropriate
  ext2simg: fix same_file() to check st_dev
  ext2simg: fix off-by-one errors causing corruption
  • Loading branch information
ebiggers authored and Gerrit Code Review committed Mar 23, 2023
2 parents 70e0f15 + 08c122f commit 8f3f2f1
Showing 1 changed file with 73 additions and 50 deletions.
123 changes: 73 additions & 50 deletions contrib/android/ext2simg.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,14 @@
#include <sparse/sparse.h>

struct {
int crc;
int sparse;
int gzip;
bool crc;
bool sparse;
bool gzip;
char *in_file;
char *out_file;
bool overwrite_input;
} params = {
.crc = 0,
.sparse = 1,
.gzip = 0,
.sparse = true,
};

#define ext2fs_fatal(Retval, Format, ...) \
Expand All @@ -60,39 +58,41 @@ static void usage(char *path)

static struct buf_item {
struct buf_item *next;
void *buf[0];
void *buf[];
} *buf_list;

static void add_chunk(ext2_filsys fs, struct sparse_file *s, blk_t chunk_start, blk_t chunk_end)
/*
* Add @num_blks blocks, starting at index @chunk_start, of the filesystem @fs
* to the sparse file @s.
*/
static void add_chunk(ext2_filsys fs, struct sparse_file *s,
blk_t chunk_start, int num_blks)
{
uint64_t len = (uint64_t)num_blks * fs->blocksize;
int64_t offset = (int64_t)chunk_start * fs->blocksize;
struct buf_item *bi;
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 (!params.overwrite_input) {
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;
}
return;
}

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);
/* The input file will be overwritten, so make a copy of the blocks. */
if (len > SIZE_MAX - sizeof(*bi))
sparse_fatal("filesystem is too large");
bi = calloc(1, sizeof(*bi) + len);
if (!bi)
sparse_fatal("out of memory");
bi->next = buf_list;
buf_list = bi;
retval = io_channel_read_blk64(fs->io, chunk_start, num_blks, bi->buf);
if (retval)
ext2fs_fatal(retval, "reading data from %s", params.in_file);

if (sparse_file_add_data(s, bi->buf, len, chunk_start) < 0)
sparse_fatal("adding data to the sparse file");
}
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)
Expand All @@ -106,13 +106,23 @@ static void free_chunks(void)
}
}

static blk_t fs_blocks_count(ext2_filsys fs)
{
blk64_t blks = ext2fs_blocks_count(fs->super);

/* libsparse assumes 32-bit block numbers. */
if ((blk_t)blks != blks)
sparse_fatal("filesystem is too large");
return blks;
}

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;
blk_t fs_blks, cur_blk;

retval = ext2fs_open(in_file, 0, 0, 0, unix_io_manager, &fs);
if (retval)
Expand All @@ -122,11 +132,9 @@ static struct sparse_file *ext_to_sparse(const char *in_file)
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;
fs_blks = fs_blocks_count(fs);

s = sparse_file_new(fs->blocksize, (uint64_t)fs->blocksize * (uint64_t)nb_blk);
s = sparse_file_new(fs->blocksize, (uint64_t)fs_blks * fs->blocksize);
if (!s)
sparse_fatal("creating sparse file");

Expand All @@ -138,24 +146,39 @@ static struct sparse_file *ext_to_sparse(const char *in_file)
* 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;
int32_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) {
/*
* Iterate through the filesystem's blocks, identifying "chunks" that
* are contiguous ranges of blocks that are in-use by the filesystem.
* Add each chunk to the sparse_file.
*/
for (cur_blk = ext2fs_get_block_bitmap_start2(fs->block_map);
cur_blk < fs_blks; ++cur_blk) {
if (ext2fs_test_block_bitmap2(fs->block_map, cur_blk)) {
/*
* @cur_blk is in-use. Append it to the pending chunk
* if there is one, otherwise start a new chunk.
*/
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);
/*
* Appending @cur_blk to the pending chunk made
* it reach the maximum length, so end it.
*/
add_chunk(fs, s, chunk_start, max_blk_per_chunk);
chunk_start = -1;
}
} else if (chunk_start != -1) {
add_chunk(fs, s, chunk_start, cur_blk);
/* @cur_blk is not in-use, so end the pending chunk. */
add_chunk(fs, s, chunk_start, cur_blk - chunk_start);
chunk_start = -1;
}
}
/* If there's still a pending chunk, end it. */
if (chunk_start != -1)
add_chunk(fs, s, chunk_start, cur_blk - 1);
add_chunk(fs, s, chunk_start, cur_blk - chunk_start);

ext2fs_free(fs);
return s;
Expand All @@ -165,14 +188,14 @@ 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)
if (stat(in, &st1) == -1)
ext2fs_fatal(errno, "stat %s\n", in);
if (lstat(out, &st2) == -1)
if (stat(out, &st2) == -1) {
if (errno == ENOENT)
return false;
ext2fs_fatal(errno, "stat %s\n", out);
return st1.st_ino == st2.st_ino;
}
return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
}

int main(int argc, char *argv[])
Expand All @@ -184,13 +207,13 @@ int main(int argc, char *argv[])
while ((opt = getopt(argc, argv, "czS")) != -1) {
switch(opt) {
case 'c':
params.crc = 1;
params.crc = true;
break;
case 'z':
params.gzip = 1;
params.gzip = true;
break;
case 'S':
params.sparse = 0;
params.sparse = false;
break;
default:
usage(argv[0]);
Expand Down

0 comments on commit 8f3f2f1

Please sign in to comment.