2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
21 #include <klay/filesystem.h>
22 #include <klay/process.h>
23 #include <klay/exception.h>
26 #include "ext4-tool.h"
30 #define ODE_SUPERBLOCK_OFFSET 1024
31 #define ODE_SUPERBLOCK_SIZE 1024
32 #define ODE_EXT2_MIN_DESC_SIZE 32
33 #define ODE_EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
34 #define ODE_EXT2_MIN_BLOCK_SIZE (1 << ODE_EXT2_MIN_BLOCK_LOG_SIZE)
36 #define ODE_EXT2_MAGIC 0xEF53
40 unsigned int divCeilSafely(unsigned int a, unsigned int b)
45 return ((a - 1) / b) + 1;
48 void execAndWait(const std::string &path, std::vector<std::string> &args)
50 runtime::Process proc(path, args);
52 int ret = proc.execute();
54 throw runtime::Exception(path + " failed for " + args.back());
56 ret = proc.waitForFinished();
57 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
58 throw runtime::Exception(path + " failed for " + args.back());
63 Ext4Tool::Ext4Tool(const std::string &src) :
64 source(src), blockSize(0), totalBlockCount(0)
67 throw runtime::Exception(source + " is not an ext2/3/4 filesystem");
76 bool Ext4Tool::isExt(const std::string &src)
79 runtime::File device(src);
83 throw runtime::Exception(src + " doesn't exist");
85 device.open(O_RDONLY);
87 device.lseek(ODE_SUPERBLOCK_OFFSET + 56, SEEK_SET);
88 device.read(&magic, 2);
90 if (magic == ODE_EXT2_MAGIC)
100 void Ext4Tool::readInfo()
102 unsigned int firstDataBlock = 0;
103 unsigned int blocksPerGroup = 0;
104 unsigned int clustersPerGroup = 0;
105 runtime::File device(source);
107 if (!device.exists())
108 throw runtime::Exception(source + " doesn't exist");
110 device.open(O_RDONLY);
112 // read totalBlockCount
113 device.lseek(ODE_SUPERBLOCK_OFFSET + 4, SEEK_SET);
114 device.read(&totalBlockCount, 4);
116 // read firstDataBlock
117 device.lseek(ODE_SUPERBLOCK_OFFSET + 20, SEEK_SET);
118 device.read(&firstDataBlock, 4);
121 device.lseek(ODE_SUPERBLOCK_OFFSET + 24, SEEK_SET);
122 device.read(&blockSize, 4);
123 blockSize = (ODE_EXT2_MIN_BLOCK_SIZE << blockSize);
125 // read blocksPerGroup
126 device.lseek(ODE_SUPERBLOCK_OFFSET + 32, SEEK_SET);
127 device.read(&blocksPerGroup, 4);
129 // read clustersPerGroup
130 device.lseek(ODE_SUPERBLOCK_OFFSET + 36, SEEK_SET);
131 device.read(&clustersPerGroup, 4);
133 unsigned int groupDescCount = divCeilSafely(totalBlockCount - firstDataBlock, blocksPerGroup);
134 int blockNbytes = clustersPerGroup / 8;
137 unsigned int descPerBlock = blockSize / ODE_EXT2_MIN_DESC_SIZE;
138 unsigned int descBlockCount = divCeilSafely(groupDescCount, descPerBlock);
140 // read first meta block
141 data group_desc(descBlockCount * blockSize);
142 device.lseek((firstDataBlock + 1) * blockSize, SEEK_SET);
143 device.read(group_desc.data(), (descBlockCount * blockSize));
145 unsigned int cnt = blockNbytes << 3;
146 unsigned int blkItr = firstDataBlock;
148 // this structure just is used for easy type-casting.
149 struct odeExtGroupDesc {
150 unsigned int blockBitmap; /* Blocks bitmap block */
151 /* skip other member */
156 unsigned int start = firstDataBlock;
157 unsigned int real_end = blocksPerGroup * groupDescCount - 1 + start;
158 size_t size = (size_t) (((real_end - start) / 8) + 1);
159 size = (size + 7) & ~3;
163 for (unsigned int i = 0; i < groupDescCount; i++) {
164 unsigned int blk = (((struct odeExtGroupDesc *)(((unsigned char *)(group_desc.data())) + i * ODE_EXT2_MIN_DESC_SIZE))->blockBitmap);
167 data block_bitmap(blockSize);
168 device.lseek(blk * blockSize, SEEK_SET);
169 device.read(block_bitmap.data(), blockSize);
171 memcpy(bitmap.data() + (blkItr >> 3), block_bitmap.data(), (cnt + 7) >> 3);
172 } catch (runtime::Exception &e) {
173 WARN(SINK, "Block " + std::to_string(blk) + " is missing");
174 memset(bitmap.data() + (blkItr >> 3), 0, (cnt + 7) >> 3);
182 unsigned int Ext4Tool::getBlockSize()
187 unsigned int Ext4Tool::getTotalBlockCount()
189 return totalBlockCount;
192 bool Ext4Tool::isUsedBlock(unsigned int blockIndex)
194 unsigned char *addr = (bitmap.data() + (blockIndex >> 3));
195 int mask = 1 << (blockIndex & 0x07);
203 void Ext4Tool::mkfs(const std::string &src)
205 static const char *mkfsPath = "/sbin/mkfs.ext4";
206 std::vector<std::string> args = {
213 execAndWait(mkfsPath, args);
216 void Ext4Tool::forceCleanUp()
218 static const char *fsckPath = "/sbin/fsck.ext4";
219 std::vector<std::string> args = {
226 execAndWait(fsckPath, args);