/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2015 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the License for the specific language governing permissions and
* limitations under the License
*/
-#include <fcntl.h>
#include <string>
#include <vector>
-#include <limits>
-#include <klay/filesystem.h>
+extern "C" {
+#include <com_err.h>
+}
+
#include <klay/process.h>
#include <klay/exception.h>
namespace ode {
-#define ODE_SUPERBLOCK_OFFSET 1024
-#define ODE_SUPERBLOCK_SIZE 1024
-#define ODE_EXT2_MIN_DESC_SIZE 32
-#define ODE_EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
-#define ODE_EXT2_MIN_BLOCK_SIZE (1 << ODE_EXT2_MIN_BLOCK_LOG_SIZE)
-
-#define ODE_EXT2_MAGIC 0xEF53
-
namespace {
-uint32_t divCeilSafely(uint32_t a, uint32_t b)
-{
- if (!a)
- return 0;
-
- if (!b)
- throw runtime::Exception("Cannot divide by zero");
-
- return ((a - 1) / b) + 1;
-}
-
void execAndWait(const std::string &path, std::vector<std::string> &args)
{
runtime::Process proc(path, args);
throw runtime::Exception(path + " failed for " + args.back());
}
+struct Ext2fsException : public runtime::Exception {
+ Ext2fsException(const std::string& prefixMsg, errcode_t err) :
+ runtime::Exception(prefixMsg + error_message(err))
+ {}
+};
+
} // namespace
-Ext4Tool::Ext4Tool(const std::string &src) :
- source(src), blockSize(0), totalBlockCount(0)
+Ext4Tool::Ext4Tool(const std::string &src)
{
- if (!isExt(src))
- throw runtime::Exception(source + " is not an ext2/3/4 filesystem");
+ errcode_t ret;
+
+ ret = ext2fs_open(src.c_str(), 0, 0, 0, unix_io_manager, &fs);
+ if (ret != 0)
+ throw Ext2fsException("ext2fs_open() failed: ", ret);
- readInfo();
+ ret = ext2fs_read_block_bitmap(fs);
+ if (ret != 0)
+ throw Ext2fsException("ext2fs_read_block_bitmap() failed: ", ret);
}
Ext4Tool::~Ext4Tool()
{
-}
-
-bool Ext4Tool::isExt(const std::string &src)
-{
- unsigned short magic;
- runtime::File device(src);
- bool ret;
-
- if (!device.exists())
- throw runtime::Exception(src + " doesn't exist");
-
- device.open(O_RDONLY);
-
- device.lseek(ODE_SUPERBLOCK_OFFSET + 56, SEEK_SET);
- device.read(&magic, 2);
-
- if (magic == ODE_EXT2_MAGIC)
- ret = true;
- else
- ret = false;
-
- device.close();
-
- return ret;
-}
-
-void Ext4Tool::readInfo()
-{
- // TODO this function should be rewritten
- uint32_t firstDataBlock = 0;
- uint32_t blocksPerGroup = 0;
- uint32_t clustersPerGroup = 0;
- uint16_t descSize = 0;
- runtime::File device(source);
-
- if (!device.exists())
- throw runtime::Exception(source + " doesn't exist");
-
- device.open(O_RDONLY);
-
- // read totalBlockCount
- device.lseek(ODE_SUPERBLOCK_OFFSET + 4, SEEK_SET);
- device.read(&totalBlockCount, sizeof(totalBlockCount));
-
- // read firstDataBlock
- device.lseek(ODE_SUPERBLOCK_OFFSET + 20, SEEK_SET);
- device.read(&firstDataBlock, sizeof(firstDataBlock));
-
- // read blockSize
- device.lseek(ODE_SUPERBLOCK_OFFSET + 24, SEEK_SET);
- device.read(&blockSize, sizeof(blockSize));
- if ((std::numeric_limits<decltype(blockSize)>::max() >> blockSize) < ODE_EXT2_MIN_BLOCK_SIZE)
- throw runtime::Exception("Block size too big"); // blockSize must be <= 21
- blockSize = (ODE_EXT2_MIN_BLOCK_SIZE << blockSize);
-
- // read blocksPerGroup
- device.lseek(ODE_SUPERBLOCK_OFFSET + 32, SEEK_SET);
- device.read(&blocksPerGroup, sizeof(blocksPerGroup));
-
- // read clustersPerGroup
- device.lseek(ODE_SUPERBLOCK_OFFSET + 36, SEEK_SET);
- device.read(&clustersPerGroup, sizeof(clustersPerGroup));
-
- // read descSize
- device.lseek(ODE_SUPERBLOCK_OFFSET + 0xFE, SEEK_SET);
- device.read(&descSize, sizeof(descSize));
- if (descSize < ODE_EXT2_MIN_DESC_SIZE) {
- descSize = ODE_EXT2_MIN_DESC_SIZE;
- }
-
- if (firstDataBlock >= totalBlockCount)
- throw runtime::Exception("Invalid block info");
- uint32_t groupDescCount = divCeilSafely(totalBlockCount - firstDataBlock, blocksPerGroup);
-
- // read group_desc
- uint32_t descPerBlock = blockSize / descSize;
- uint32_t descBlockCount = divCeilSafely(groupDescCount, descPerBlock);
-
- // read first meta block
- if (descBlockCount > std::numeric_limits<BinaryData::size_type>::max() / blockSize)
- throw runtime::Exception("Size too big for BinaryData");
- BinaryData group_desc(descBlockCount * blockSize);
- // firstDataBlock < totalBlockCount so no overflow is possible
- device.lseek((firstDataBlock + 1) * blockSize, SEEK_SET);
- device.read(group_desc.data(), group_desc.size());
-
- uint32_t blkItr = firstDataBlock;
-
- // this structure just is used for easy type-casting.
- struct odeExtGroupDesc {
- uint32_t blockBitmap; /* Blocks bitmap block */
- /* skip other member */
- };
-
- // read bitmap
- {
- uint32_t start = firstDataBlock;
- uint32_t real_end = totalBlockCount - 1;
-
- uint32_t size = (real_end - start) / 8 + 1;
- size = (size + 7) & ~3;
- if (std::numeric_limits<size_t>::max() <= size)
- throw runtime::Exception("Bitmap size too big");
-
- bitmap.resize(size);
- }
-
- if (groupDescCount >= group_desc.size() / descSize)
- throw runtime::Exception("Group descriptors buffer too small");
-
- if (clustersPerGroup > std::numeric_limits<size_t>::max() - 7)
- throw runtime::Exception("Too many clusters per group");
-
- if (groupDescCount > (std::numeric_limits<decltype(blkItr)>::max() - blkItr) / clustersPerGroup + 1)
- throw runtime::Exception("Block iterator may get too big");
-
- if (((blkItr + clustersPerGroup * (groupDescCount - 1)) >> 3) + ((clustersPerGroup + 7) >> 3) > bitmap.size())
- throw runtime::Exception("Bitmap size too small");
-
- for (uint32_t i = 0; i < groupDescCount; i++) {
- uint32_t blk = reinterpret_cast<odeExtGroupDesc*>(group_desc.data() + i * descSize)->blockBitmap;
-
- try {
- BinaryData block_bitmap(blockSize);
-
- if (blk > std::numeric_limits<off_t>::max() / blockSize)
- throw runtime::Exception("Block bitmap index too big");
-
- device.lseek(blk * blockSize, SEEK_SET);
- device.read(block_bitmap.data(), blockSize);
-
- memcpy(bitmap.data() + (blkItr >> 3), block_bitmap.data(), (clustersPerGroup + 7) >> 3);
- } catch (runtime::Exception &e) {
- WARN(SINK, "Block " + std::to_string(blk) + " is missing");
- memset(bitmap.data() + (blkItr >> 3), 0, (clustersPerGroup + 7) >> 3);
- }
- blkItr += clustersPerGroup;
- }
-
- device.close();
+ errcode_t err = ext2fs_close_free(&fs);
+ if (err != 0)
+ ERROR(SINK, "ext2fs_close_free() failed: " + std::string(error_message(err)));
}
uint32_t Ext4Tool::getBlockSize()
{
- return blockSize;
+ return fs->blocksize;
}
uint32_t Ext4Tool::getTotalBlockCount()
{
- return totalBlockCount;
+ return fs->super->s_blocks_count;
}
bool Ext4Tool::isUsedBlock(uint32_t blockIndex)
{
- unsigned char *addr = (bitmap.data() + (blockIndex >> 3));
- unsigned char mask = 1 << (blockIndex & 0x07);
-
- if (mask & *addr)
- return true;
-
- return false;
+ return ext2fs_test_block_bitmap2(fs->block_map, blockIndex);
}
void Ext4Tool::mkfs(const std::string &src)
execAndWait(mkfsPath, args);
}
-void Ext4Tool::forceCleanUp()
+void Ext4Tool::forceCleanUp(const std::string &src)
{
static const char *fsckPath = "/sbin/fsck.ext4";
std::vector<std::string> args = {
fsckPath,
"-f",
"-y",
- source
+ src
};
execAndWait(fsckPath, args);