Fix erofs-utils 1.7 compatibility
Test: th
Change-Id: I273fb8937e584fadf8fe7205be75c049a474bdba
diff --git a/common/utils.h b/common/utils.h
index 6c6337f..0c8c13f 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -642,9 +642,10 @@
}
} deferrer;
-#define TOKENPASTE(x, y) x##y
-#define DEFER \
- auto TOKENPASTE(_deferred_lambda_call, __COUNTER__) = deferrer \
- << [&]() mutable
+#define TOKENPASTE1(x, y) x##y
+#define TOKENPASTE2(x, y) TOKENPASTE1(x, y)
+#define DEFER \
+ auto TOKENPASTE2(_deferred_lambda_call, __COUNTER__) = deferrer \
+ << [&]() mutable
#endif // UPDATE_ENGINE_COMMON_UTILS_H_
diff --git a/lz4diff/lz4diff_compress_unittest.cc b/lz4diff/lz4diff_compress_unittest.cc
index b4b56d2..d05c6be 100644
--- a/lz4diff/lz4diff_compress_unittest.cc
+++ b/lz4diff/lz4diff_compress_unittest.cc
@@ -47,21 +47,20 @@
static void ExtractErofsImage(const char* erofs_image,
const char* inode_path,
Blob* output) {
- // EROFS has plenty of global variable usage. Protect calls to EROFS APIs with
- // global mutex.
- // TODO(b/202784930) Replace erofs-utils with a cleaner and more C++ friendly
- // library. (Or turn erofs-utils into one)
- static std::mutex mutex;
- std::lock_guard lock(mutex);
- auto err = dev_open_ro(erofs_image);
+ struct erofs_sb_info sbi {};
+ auto err = dev_open_ro(&sbi, erofs_image);
ASSERT_EQ(err, 0);
- DEFER { dev_close(); };
+ DEFER {
+ dev_close(&sbi);
+ };
- err = erofs_read_superblock();
+ err = erofs_read_superblock(&sbi);
ASSERT_EQ(err, 0);
- struct erofs_inode inode;
+ struct erofs_inode inode {
+ .sbi = &sbi
+ };
err = erofs_ilookup(inode_path, &inode);
- ASSERT_EQ(err, 0);
+ ASSERT_EQ(err, 0) << strerror(-err);
output->resize(inode.i_size);
err = erofs_pread(&inode,
reinterpret_cast<char*>(output->data()),
diff --git a/payload_generator/erofs_filesystem.cc b/payload_generator/erofs_filesystem.cc
index 508c9a1..32a5fc5 100644
--- a/payload_generator/erofs_filesystem.cc
+++ b/payload_generator/erofs_filesystem.cc
@@ -28,6 +28,7 @@
#include <erofs/dir.h>
#include <erofs/io.h>
#include <erofs_fs.h>
+#include <erofs/internal.h>
#include "erofs_iterate.h"
#include "lz4diff/lz4diff.pb.h"
@@ -43,6 +44,7 @@
namespace {
static constexpr int GetOccupiedSize(const struct erofs_inode* inode,
+ size_t block_size,
erofs_off_t* size) {
*size = 0;
switch (inode->datalayout) {
@@ -51,9 +53,9 @@
case EROFS_INODE_CHUNK_BASED:
*size = inode->i_size;
break;
- case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
- case EROFS_INODE_FLAT_COMPRESSION:
- *size = inode->u.i_blocks * EROFS_BLKSIZ;
+ case EROFS_INODE_COMPRESSED_FULL:
+ case EROFS_INODE_COMPRESSED_COMPACT:
+ *size = inode->u.i_blocks * block_size;
break;
default:
LOG(ERROR) << "unknown datalayout " << inode->datalayout;
@@ -166,48 +168,40 @@
} // namespace
-static_assert(kBlockSize == EROFS_BLKSIZ);
-
std::unique_ptr<ErofsFilesystem> ErofsFilesystem::CreateFromFile(
const std::string& filename, const CompressionAlgorithm& algo) {
if (!IsErofsImage(filename.c_str())) {
return {};
}
- // erofs-utils makes heavy use of global variables. Hence its functions aren't
- // thread safe. For example, it stores a global int holding file descriptors
- // to the opened EROFS image. It doesn't even support opening more than 1
- // imaeg at a time.
- // TODO(b/202784930) Replace erofs-utils with a cleaner and more C++ friendly
- // library. (Or turn erofs-utils into one)
- static std::mutex m;
- std::lock_guard g{m};
+ struct erofs_sb_info sbi {};
- if (const auto err = dev_open_ro(filename.c_str()); err) {
+ if (const auto err = dev_open_ro(&sbi, filename.c_str()); err) {
PLOG(INFO) << "Failed to open " << filename;
return nullptr;
}
DEFER {
- dev_close();
+ dev_close(&sbi);
};
- if (const auto err = erofs_read_superblock(); err) {
+ if (const auto err = erofs_read_superblock(&sbi); err) {
PLOG(INFO) << "Failed to parse " << filename << " as EROFS image";
return nullptr;
}
+ const auto block_size = 1UL << sbi.blkszbits;
struct stat st {};
- if (const auto err = fstat(erofs_devfd, &st); err) {
+ if (const auto err = fstat(sbi.devfd, &st); err) {
PLOG(ERROR) << "Failed to stat() " << filename;
return nullptr;
}
const time_t time = sbi.build_time;
std::vector<File> files;
- if (!ErofsFilesystem::GetFiles(filename, &files, algo)) {
- return nullptr;
- }
+ CHECK(ErofsFilesystem::GetFiles(&sbi, filename, &files, algo))
+ << "Failed to parse EROFS image " << filename;
LOG(INFO) << "Parsed EROFS image of size " << st.st_size << " built in "
<< ctime(&time) << " " << filename
- << ", number of files: " << files.size();
+ << ", number of files: " << files.size()
+ << ", block size: " << block_size;
LOG(INFO) << "Using compression algo " << algo << " for " << filename;
// private ctor doesn't work with make_unique
return std::unique_ptr<ErofsFilesystem>(
@@ -219,51 +213,59 @@
return true;
}
-bool ErofsFilesystem::GetFiles(const std::string& filename,
+bool ErofsFilesystem::GetFiles(struct erofs_sb_info* sbi,
+ const std::string& filename,
std::vector<File>* files,
const CompressionAlgorithm& algo) {
size_t unaligned_bytes = 0;
- erofs_iterate_root_dir(&sbi, [&](struct erofs_iterate_dir_context* p_info) {
- const auto& info = *p_info;
- if (info.ctx.de_ftype != EROFS_FT_REG_FILE) {
- return 0;
- }
- struct erofs_inode inode {};
- inode.nid = info.ctx.de_nid;
- int err = erofs_read_inode_from_disk(&inode);
- if (err) {
- LOG(ERROR) << "Failed to read inode " << inode.nid;
- return err;
- }
- const auto uncompressed_size = inode.i_size;
- erofs_off_t compressed_size = 0;
- if (uncompressed_size == 0) {
- return 0;
- }
- err = GetOccupiedSize(&inode, &compressed_size);
- if (err) {
- LOG(FATAL) << "Failed to get occupied size for " << filename;
- return err;
- }
- // For EROFS_INODE_FLAT_INLINE , most blocks are stored on aligned
- // addresses. Except the last block, which is stored right after the
- // inode. These nodes will have a slight amount of data unaligned, which
- // is fine.
+ const auto block_size = 1UL << sbi->blkszbits;
+ const auto err = erofs_iterate_root_dir(
+ sbi, [&](struct erofs_iterate_dir_context* p_info) {
+ const auto& info = *p_info;
+ if (info.ctx.de_ftype != EROFS_FT_REG_FILE) {
+ return 0;
+ }
+ struct erofs_inode inode {};
+ inode.nid = info.ctx.de_nid;
+ inode.sbi = sbi;
+ int err = erofs_read_inode_from_disk(&inode);
+ if (err) {
+ LOG(ERROR) << "Failed to read inode " << inode.nid;
+ return err;
+ }
+ const auto uncompressed_size = inode.i_size;
+ erofs_off_t compressed_size = 0;
+ if (uncompressed_size == 0) {
+ return 0;
+ }
+ err = GetOccupiedSize(&inode, block_size, &compressed_size);
+ if (err) {
+ LOG(FATAL) << "Failed to get occupied size for " << filename;
+ return err;
+ }
+ // For EROFS_INODE_FLAT_INLINE , most blocks are stored on aligned
+ // addresses. Except the last block, which is stored right after the
+ // inode. These nodes will have a slight amount of data unaligned, which
+ // is fine.
- File file;
- file.name = info.path;
- file.compressed_file_info.zero_padding_enabled =
- erofs_sb_has_lz4_0padding();
- file.is_compressed = compressed_size != uncompressed_size;
+ File file;
+ file.name = info.path;
+ file.compressed_file_info.zero_padding_enabled =
+ erofs_sb_has_lz4_0padding(sbi);
+ file.is_compressed = compressed_size != uncompressed_size;
- file.file_stat.st_size = uncompressed_size;
- file.file_stat.st_ino = inode.nid;
- FillExtentInfo(&file, filename, &inode, &unaligned_bytes);
- file.compressed_file_info.algo = algo;
+ file.file_stat.st_size = uncompressed_size;
+ file.file_stat.st_ino = inode.nid;
+ FillExtentInfo(&file, filename, &inode, &unaligned_bytes);
+ file.compressed_file_info.algo = algo;
- files->emplace_back(std::move(file));
- return 0;
- });
+ files->emplace_back(std::move(file));
+ return 0;
+ });
+ if (err) {
+ LOG(ERROR) << "EROFS files iteration filed " << strerror(-err);
+ return false;
+ }
for (auto& file : *files) {
NormalizeExtents(&file.extents);
diff --git a/payload_generator/erofs_filesystem.h b/payload_generator/erofs_filesystem.h
index d0abcb3..b10fc98 100644
--- a/payload_generator/erofs_filesystem.h
+++ b/payload_generator/erofs_filesystem.h
@@ -20,6 +20,8 @@
#include "update_engine/payload_generator/filesystem_interface.h"
#include "update_engine/payload_generator/delta_diff_generator.h"
+struct erofs_sb_info;
+
namespace chromeos_update_engine {
class ErofsFilesystem final : public FilesystemInterface {
@@ -50,7 +52,8 @@
// space.
// <metadata>: With the rest of ext2 metadata blocks, such as superblocks
// and bitmap tables.
- static bool GetFiles(const std::string& filename,
+ static bool GetFiles(struct erofs_sb_info* sbi,
+ const std::string& filename,
std::vector<File>* files,
const CompressionAlgorithm& algo);
diff --git a/payload_generator/erofs_iterate.h b/payload_generator/erofs_iterate.h
index ac9d67e..ef37418 100644
--- a/payload_generator/erofs_iterate.h
+++ b/payload_generator/erofs_iterate.h
@@ -13,6 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
+#ifndef UPDATE_ENGINE_PAYLOAD_GENERATOR_EROFS_ITERATE_H_
+#define UPDATE_ENGINE_PAYLOAD_GENERATOR_EROFS_ITERATE_H_
#include <string>
@@ -36,19 +38,24 @@
// Callable shold be a functor like
// std::function<int(struct erofs_inode_info *)>
template <typename Callable>
-int erofs_iterate_root_dir(const struct erofs_sb_info* sbi, Callable cb) {
- struct erofs_inode dir {
- .nid = sbi->root_nid
+int erofs_iterate_root_dir(struct erofs_sb_info* sbi, Callable cb) {
+ CHECK_NE(sbi, nullptr);
+ struct erofs_inode root_dir {
+ .sbi = sbi, .nid = sbi->root_nid
};
- int err = erofs_read_inode_from_disk(&dir);
+ int err = erofs_read_inode_from_disk(&root_dir);
if (err) {
- LOG(ERROR) << "Failed to read inode " << sbi->root_nid << " from disk";
+ LOG(ERROR) << "Failed to read inode " << sbi->root_nid << " from disk "
+ << strerror(-err);
return err;
}
struct erofs_iterate_dir_context param {
- .ctx.dir = &dir, .ctx.pnid = sbi->root_nid,
+ .ctx.dir = &root_dir, .ctx.pnid = sbi->root_nid,
.ctx.cb = [](struct erofs_dir_context* arg) -> int {
auto ctx = reinterpret_cast<erofs_iterate_dir_context*>(arg);
+ const auto parent_dir = ctx->ctx.dir;
+ const auto sbi = ctx->ctx.dir->sbi;
+ CHECK_NE(sbi, nullptr);
auto& path = ctx->path;
const auto len = path.size();
path.push_back('/');
@@ -58,14 +65,21 @@
const auto err = (*cb)(ctx);
if (!err && !ctx->ctx.dot_dotdot && ctx->ctx.de_ftype == EROFS_FT_DIR) {
// recursively walk into subdirectories
- erofs_inode dir{.nid = ctx->ctx.de_nid};
+ struct erofs_inode dir {
+ .sbi = sbi, .nid = ctx->ctx.de_nid
+ };
if (const int err = erofs_read_inode_from_disk(&dir); err) {
+ LOG(FATAL) << "Failed to erofs_read_inode_from_disk("
+ << ctx->ctx.de_nid << ") " << strerror(-err);
return err;
}
ctx->ctx.dir = &dir;
if (const auto err = erofs_iterate_dir(&ctx->ctx, false); err) {
+ LOG(FATAL) << "Failed to erofs_iterate_dir(" << ctx->ctx.de_nid
+ << ") " << strerror(-err);
return err;
}
+ ctx->ctx.dir = parent_dir;
}
path.resize(len);
return err;
@@ -74,3 +88,5 @@
};
return erofs_iterate_dir(¶m.ctx, false);
}
+
+#endif