From d00c9626ac9c04ec42b82c3096e43ff6da6427b6 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 9 Sep 2024 19:21:14 -0400 Subject: [PATCH] Handle non-inline files that need to be EROFS_INODE_CHUNK_BASED Signed-off-by: Colin Walters --- libcomposefs/lcfs-writer-erofs.c | 41 +++++++++++++++++++------- tests/assets/bigfile-xattr.dump | 2 ++ tests/assets/bigfile-xattr.dump.sha256 | 1 + tests/meson.build | 1 + 4 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 tests/assets/bigfile-xattr.dump create mode 100644 tests/assets/bigfile-xattr.dump.sha256 diff --git a/libcomposefs/lcfs-writer-erofs.c b/libcomposefs/lcfs-writer-erofs.c index b7ac6e6e..1bc401ca 100644 --- a/libcomposefs/lcfs-writer-erofs.c +++ b/libcomposefs/lcfs-writer-erofs.c @@ -638,6 +638,7 @@ static uint64_t compute_erofs_inode_padding_for_tail(struct lcfs_node_s *node, /* Didn't fit, don't inline the tail. */ node->erofs_n_blocks++; node->erofs_tailsize = 0; + return round_up(pos, EROFS_BLKSIZ) - pos; } return 0; @@ -817,6 +818,17 @@ static int write_erofs_dentries(struct lcfs_ctx_s *ctx, struct lcfs_node_s *node return 0; } +static int write_empty_chunks(struct lcfs_ctx_s *ctx, uint32_t chunk_count) +{ + for (size_t i = 0; i < chunk_count; i++) { + uint32_t empty_chunk = 0xFFFFFFFF; + int ret = lcfs_write(ctx, &empty_chunk, sizeof(empty_chunk)); + if (ret < 0) + return ret; + } + return 0; +} + static int write_erofs_inode_data(struct lcfs_ctx_s *ctx, struct lcfs_node_s *node) { struct lcfs_ctx_erofs_s *ctx_erofs = (struct lcfs_ctx_erofs_s *)ctx; @@ -1012,9 +1024,8 @@ static int write_erofs_inode_data(struct lcfs_ctx_s *ctx, struct lcfs_node_s *no if (ret < 0) return ret; } - } else if (type == S_IFREG) { + } else if (type == S_IFREG && node->erofs_tailsize > 0) { if (node->content != NULL) { - if (node->erofs_tailsize) { uint64_t file_size = node->inode.st_size; ret = lcfs_write(ctx, node->content + file_size - @@ -1022,18 +1033,14 @@ static int write_erofs_inode_data(struct lcfs_ctx_s *ctx, struct lcfs_node_s *no node->erofs_tailsize); if (ret < 0) return ret; - } } else { // Currently we assume this fits within a single block assert(chunk_count <= LCFS_MAX_NONINLINE_CHUNKS); assert(node->erofs_n_blocks == 0 || node->erofs_n_blocks == 1); - for (size_t i = 0; i < chunk_count; i++) { - uint32_t empty_chunk = 0xFFFFFFFF; - ret = lcfs_write(ctx, &empty_chunk, - sizeof(empty_chunk)); - if (ret < 0) - return ret; + ret = write_empty_chunks(ctx, chunk_count); + if (ret < 0) { + return ret; } } } @@ -1071,7 +1078,21 @@ static int write_erofs_file_content(struct lcfs_ctx_s *ctx, struct lcfs_node_s * uint8_t *target; bool has_blocks = node->erofs_n_blocks > 0; if (type == S_IFREG && has_blocks) { - assert(node->content != NULL); + // If this is a non-inline file, then we need to write at most + // a single block-sized chunk. + if (node->content == NULL) { + assert(node->erofs_tailsize == 0); + uint32_t chunkbits; + uint32_t chunk_count; + erofs_compute_chunking(node->inode.st_size, &chunkbits, + &chunk_count); + // Currently we assume this fits within a single block + assert(chunk_count <= LCFS_MAX_NONINLINE_CHUNKS); + assert(node->erofs_n_blocks == 1); + // Note early return here + return write_empty_chunks(ctx, chunk_count); + } + // If it's an inline file, provide the content to write target = node->content; } else if (type == S_IFLNK && has_blocks) { assert(node->payload != NULL); diff --git a/tests/assets/bigfile-xattr.dump b/tests/assets/bigfile-xattr.dump new file mode 100644 index 00000000..3a80f03c --- /dev/null +++ b/tests/assets/bigfile-xattr.dump @@ -0,0 +1,2 @@ +/ 4096 40755 2 0 0 0 0.0 - - - +/bigfile 9001899274941000 100777 1 0 0 0 0.0 - - - user.foo= diff --git a/tests/assets/bigfile-xattr.dump.sha256 b/tests/assets/bigfile-xattr.dump.sha256 new file mode 100644 index 00000000..99bc4995 --- /dev/null +++ b/tests/assets/bigfile-xattr.dump.sha256 @@ -0,0 +1 @@ +5bdb37d78dcf03b4ab1adc9a2d5212d3d95213b41628939f5fe3769f93d927cc diff --git a/tests/meson.build b/tests/meson.build index e8dc30b2..577bac1c 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -5,6 +5,7 @@ test_assets_small = [ 'special.dump', 'longlink.dump', 'bigfile.dump', + 'bigfile-xattr.dump', 'special_v1.dump', 'honggfuzz-long-symlink.dump', 'no-newline.dump',