blob: 9954fad1288c36dcbade089f66b574a0d2adc16a [file] [edit]
// Copyright 2025 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <init/libpreservation/ext2fs.h>
namespace libpreservation {
Ext2fsImpl::Ext2fsImpl(ext2_filsys fs) : fs_(fs) {}
Ext2fsImpl::~Ext2fsImpl() {
if (fs_) {
ext2fs_close(fs_);
}
}
bool Ext2fsImpl::LookupInode(const base::FilePath& path, ext2_ino_t* inode) {
errcode_t err;
ext2_ino_t cwd = EXT2_ROOT_INO;
err = ext2fs_namei(fs_, EXT2_ROOT_INO, cwd, path.value().c_str(), inode);
if (err) {
return false;
}
return true;
}
bool Ext2fsImpl::Mkdir(ext2_ino_t parent, const std::string& name) {
errcode_t err;
err = ext2fs_mkdir(fs_, parent, 0, name.c_str());
if (err) {
LOG(ERROR) << "Failed to create directory: " << name << err;
return false;
}
return true;
}
bool Ext2fsImpl::NewInode(ext2_ino_t parent, ext2_ino_t* inode) {
errcode_t err;
err = ext2fs_new_inode(fs_, parent, LINUX_S_IFREG, nullptr, inode);
if (err) {
LOG(ERROR) << "Failed to create new inode; Error: " << err;
return false;
}
return true;
}
bool Ext2fsImpl::LinkFile(ext2_ino_t parent,
const std::string& name,
ext2_ino_t inode) {
errcode_t err;
err = ext2fs_link(fs_, parent, name.c_str(), inode, EXT2_FT_REG_FILE);
if (err) {
LOG(ERROR) << "Failed to create link for file: " << name
<< "; Error: " << err;
return false;
}
return true;
}
bool Ext2fsImpl::InitInodeExtentHeader(ext2_ino_t inode,
ext2_inode* inode_struct) {
errcode_t err;
ext2_extent_handle_t handle;
err = ext2fs_extent_open2(fs_, inode, inode_struct, &handle);
if (err) {
LOG(ERROR) << "Failed to setup extent header for inode: " << inode
<< "; Error: " << err;
return false;
}
ext2fs_extent_free(handle);
return true;
}
void Ext2fsImpl::MarkInodeInUseAsFile(ext2_ino_t inode) {
ext2fs_inode_alloc_stats2(fs_, inode, /*inuse=*/1, /*isdir=*/0);
}
bool Ext2fsImpl::PersistInode(ext2_ino_t inode, ext2_inode inode_struct) {
errcode_t err;
err = ext2fs_write_new_inode(fs_, inode, &inode_struct);
if (err) {
LOG(ERROR) << "Failed to write inode: " << inode << "; Error: " << err;
return err;
}
return true;
}
bool Ext2fsImpl::FixedGoalFallocate(ext2_ino_t inode,
blk64_t goal,
blk64_t start,
blk64_t length) {
errcode_t err;
err = ext2fs_fallocate(fs_,
EXT2_FALLOCATE_INIT_BEYOND_EOF |
EXT2_FALLOCATE_FORCE_INIT |
EXT2_FALLOCATE_FIXED_GOAL,
inode, NULL, goal, start, length);
if (err) {
LOG(ERROR) << "Extent (start, length, goal): " << start << " " << length
<< " " << goal;
LOG(ERROR) << "Failed to allocate extent for inode: " << inode
<< "; Error: " << err;
return false;
}
return true;
}
bool Ext2fsImpl::Unlink(ext2_ino_t parent, const std::string& name) {
errcode_t err;
err = ext2fs_unlink(fs_, parent, name.c_str(), 0, 0);
if (err) {
LOG(ERROR) << "Failed to unlink file: " << name << "; Error: " << err;
return false;
}
return true;
}
std::unique_ptr<Ext2fs> Ext2fsImpl::Generate(const base::FilePath& device) {
ext2_filsys fs;
if (ext2fs_open(device.value().c_str(), EXT2_FLAG_RW | EXT2_FLAG_DIRECT_IO, 0,
0, unix_io_manager, &fs)) {
LOG(ERROR) << "Failed to open ext4 filesystem";
return nullptr;
}
if (ext2fs_read_bitmaps(fs)) {
LOG(ERROR) << "Failed to read bitmaps";
return nullptr;
}
return std::make_unique<Ext2fsImpl>(fs);
}
} // namespace libpreservation