Skip to content

Commit 66f75a5

Browse files
committed
added image check functionality (only allocator for now)
1 parent 6123bc1 commit 66f75a5

File tree

7 files changed

+166
-10
lines changed

7 files changed

+166
-10
lines changed

orbisFSTool/OrbisFSBlockAllocator.cpp

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,47 @@
1313
using namespace orbisFSTool;
1414

1515
#pragma mark OrbisFSBlockAllocator
16-
OrbisFSBlockAllocator::OrbisFSBlockAllocator(OrbisFSImage *parent, uint32_t allocatorInfoBlock)
17-
: _parent(parent)
16+
OrbisFSBlockAllocator::OrbisFSBlockAllocator(OrbisFSImage *parent, uint32_t allocatorInfoBlock, bool virtualMode)
17+
: _parent(parent), _blockSize(_parent->getBlocksize())
1818
, _info(NULL)
1919
{
20-
_info = (OrbisFSAllocatorInfoElem_t*)_parent->getBlock(allocatorInfoBlock);
20+
if (virtualMode) {
21+
_virtualMem[allocatorInfoBlock] = {(const void *)_parent->getBlock(allocatorInfoBlock),_blockSize};
22+
}
23+
24+
_info = (OrbisFSAllocatorInfoElem_t*)getBlock(allocatorInfoBlock);
2125
}
2226

2327
OrbisFSBlockAllocator::~OrbisFSBlockAllocator(){
2428
//
2529
}
2630

2731
#pragma mark OrbisFSBlockAllocator private
32+
uint8_t *OrbisFSBlockAllocator::getBlock(uint32_t blkNum){
33+
if (_virtualMem.size() == 0){
34+
return _parent->getBlock(blkNum);
35+
}else{
36+
/*
37+
We're in virtual mode!
38+
Cache unseed blocks and return everything only from cache
39+
*/
40+
auto c = _virtualMem.find(blkNum);
41+
if (c != _virtualMem.end()) return c->second.data();
42+
43+
_virtualMem[blkNum] = {(const void *)_parent->getBlock(blkNum),_blockSize};
44+
45+
try {
46+
return _virtualMem.at(blkNum).data();
47+
} catch (...) {
48+
reterror("OrbisFSBlockAllocator virtual mode error!");
49+
}
50+
}
51+
}
52+
2853
#pragma mark OrbisFSBlockAllocator public
2954
uint64_t OrbisFSBlockAllocator::getTotalBlockNum(){
3055
uint64_t ret = 1;
31-
uint32_t maxEntries = _parent->getBlocksize() / sizeof(*_info);
56+
uint32_t maxEntries = _blockSize / sizeof(*_info);
3257
for (uint32_t i=0; i<maxEntries; i++) {
3358
if (_info[i].bitmapBlk.type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
3459
ret += _info[i].totalBlocks;
@@ -38,7 +63,7 @@ uint64_t OrbisFSBlockAllocator::getTotalBlockNum(){
3863

3964
uint64_t OrbisFSBlockAllocator::getFreeBlocksNum(){
4065
uint64_t ret = 0;
41-
uint32_t maxEntries = _parent->getBlocksize() / sizeof(*_info);
66+
uint32_t maxEntries = _blockSize / sizeof(*_info);
4267
for (uint32_t i=0; i<maxEntries; i++) {
4368
if (_info[i].bitmapBlk.type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
4469
ret += _info[i].freeBlocks;
@@ -47,16 +72,39 @@ uint64_t OrbisFSBlockAllocator::getFreeBlocksNum(){
4772
}
4873

4974
bool OrbisFSBlockAllocator::isBlockFree(uint32_t blkNum){
50-
uint32_t maxEntries = _parent->getBlocksize() / sizeof(*_info);
75+
uint32_t maxEntries = _blockSize / sizeof(*_info);
5176
for (uint32_t i=0; i<maxEntries; i++) {
5277
OrbisFSAllocatorInfoElem_t ci = _info[i];
5378
if (ci.bitmapBlk.type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
5479
if (blkNum >= ci.totalBlocks) {
5580
blkNum -= ci.totalBlocks;
5681
continue;
5782
}
58-
uint8_t *bitmap = _parent->getBlock(ci.bitmapBlk.blk);
59-
return (bitmap[blkNum/8] >> (blkNum & 3)) & 1;
83+
uint8_t *bitmap = getBlock(ci.bitmapBlk.blk);
84+
uint32_t blkIdx = blkNum >> 3;
85+
uint32_t blkOff = blkNum & 7;
86+
return (bitmap[blkIdx] >> blkOff) & 1;
87+
}
88+
reterror("failed to find block in bitmap");
89+
}
90+
91+
void OrbisFSBlockAllocator::freeBlock(uint32_t blkNum){
92+
uint32_t maxEntries = _blockSize / sizeof(*_info);
93+
for (uint32_t i=0; i<maxEntries; i++) {
94+
OrbisFSAllocatorInfoElem_t *ci = &_info[i];
95+
if (ci->bitmapBlk.type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
96+
if (blkNum >= ci->totalBlocks) {
97+
blkNum -= ci->totalBlocks;
98+
continue;
99+
}
100+
uint8_t *bitmap = getBlock(ci->bitmapBlk.blk);
101+
uint32_t blkIdx = blkNum >> 3;
102+
uint32_t blkOff = blkNum & 7;
103+
retassure(((bitmap[blkIdx] >> blkOff) & 1) == 0, "double free detected!");
104+
bitmap[blkIdx] |= (1<<blkOff);
105+
ci->freeBlocks++;
106+
retassure(ci->freeBlocks <= ci->totalBlocks, "Error: freeBlocks > totalBlocks");
107+
return;
60108
}
61109
reterror("failed to find block in bitmap");
62110
}

orbisFSTool/OrbisFSBlockAllocator.hpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,32 @@
1010

1111
#include "OrbisFSFormat.h"
1212

13+
#include <libgeneral/Mem.hpp>
14+
15+
#include <map>
16+
1317
#include <stdint.h>
1418

1519
namespace orbisFSTool {
1620
class OrbisFSImage;
1721

1822
class OrbisFSBlockAllocator {
1923
OrbisFSImage *_parent; //not owned
24+
const uint32_t _blockSize;
2025

2126
OrbisFSAllocatorInfoElem_t *_info;
27+
28+
std::map<uint32_t,tihmstar::Mem> _virtualMem;
29+
30+
uint8_t *getBlock(uint32_t blkNum);
2231
public:
23-
OrbisFSBlockAllocator(OrbisFSImage *parent, uint32_t allocatorInfoBlock);
32+
OrbisFSBlockAllocator(OrbisFSImage *parent, uint32_t allocatorInfoBlock, bool virtualMode = false);
2433
~OrbisFSBlockAllocator();
2534

2635
uint64_t getTotalBlockNum();
2736
uint64_t getFreeBlocksNum();
2837
bool isBlockFree(uint32_t blkNum);
38+
void freeBlock(uint32_t blkNum);
2939
};
3040

3141
}

orbisFSTool/OrbisFSFile.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ uint8_t *OrbisFSFile::getDataBlock(uint64_t num){
5454
retassure(_node->dataLnk[0].type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad dataLnk type 0x%02x",_node->dataLnk[0].type);
5555
if (_node->fatStages == 1){
5656
retassure(num < ARRAYOF(_node->dataLnk), "1 level stage lookup out of bounds");
57+
retassure(_node->dataLnk[num].type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad dataLnk type 0x%02x",_node->dataLnk[num].type);
5758
return _parent->getBlock(_node->dataLnk[num].blk);
5859
}
5960

@@ -77,6 +78,7 @@ uint8_t *OrbisFSFile::getDataBlock(uint64_t num){
7778
/*
7879
Stage 2 lookup
7980
*/
81+
retassure(num < linkElemsPerPage, "Trying to access out of bounds block on stage 3 lookup");
8082
fat = &fat[num];
8183
retassure(fat->type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad fat type 0x%02x",fat->type);
8284
return _parent->getBlock(fat->blk);
@@ -92,6 +94,41 @@ uint8_t *OrbisFSFile::getDataForOffset(uint64_t offset){
9294
return &blk[blkOffset];
9395
}
9496

97+
std::vector<uint32_t> OrbisFSFile::getAllAllocatedBlocks(){
98+
const uint32_t linkElemsPerPage = _blockSize/sizeof(OrbisFSChainLink_t);
99+
std::vector<uint32_t> ret;
100+
if (!_node->fatStages){
101+
return {};
102+
}else if (_node->fatStages == 1) {
103+
for (int i=0; i<ARRAYOF(_node->dataLnk); i++) {
104+
if (_node->dataLnk[i].type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
105+
ret.push_back(_node->dataLnk[i].blk);
106+
}
107+
}else if (_node->fatStages == 2){
108+
retassure(_node->dataLnk[0].type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad dataLnk type 0x%02x",_node->dataLnk[0].type);
109+
OrbisFSChainLink_t *fat = (OrbisFSChainLink_t*)_parent->getBlock(_node->dataLnk[0].blk);
110+
ret.push_back(_node->dataLnk[0].blk);
111+
112+
for (int i=0; i < linkElemsPerPage; i++) {
113+
if (fat[i].type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
114+
ret.push_back(fat[i].blk);
115+
}
116+
}else if (_node->fatStages == 3){
117+
118+
reterror("TODO");
119+
}else{
120+
reterror("%d fat stages currently not supported",_node->fatStages);
121+
}
122+
123+
//also count resource blocks
124+
for (int i=0; i<ARRAYOF(_node->resourceLnk); i++) {
125+
if (_node->resourceLnk[i].type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
126+
ret.push_back(_node->resourceLnk[i].blk);
127+
}
128+
129+
return ret;
130+
}
131+
95132
#pragma mark OrbisFSFile public
96133
#pragma mark IO operations
97134
uint64_t OrbisFSFile::size(){

orbisFSTool/OrbisFSFile.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#include "OrbisFSFormat.h"
1212

13+
#include <vector>
14+
1315
#include <stdint.h>
1416
#include <stddef.h>
1517

@@ -27,6 +29,7 @@ class OrbisFSFile {
2729

2830
uint8_t *getDataBlock(uint64_t num);
2931
uint8_t *getDataForOffset(uint64_t offset);
32+
std::vector<uint32_t> getAllAllocatedBlocks();
3033
public:
3134
OrbisFSFile(OrbisFSImage *parent, OrbisFSInode_t *node, bool noFilemodeChecks = false);
3235
~OrbisFSFile();
@@ -46,6 +49,7 @@ class OrbisFSFile {
4649

4750
#pragma mark friends
4851
friend OrbisFSInodeDirectory;
52+
friend OrbisFSImage;
4953
};
5054

5155
}

orbisFSTool/OrbisFSImage.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,38 @@ std::shared_ptr<OrbisFSFile> OrbisFSImage::openFileNode(OrbisFSInode_t *node, bo
222222
return std::make_shared<OrbisFSFile>(this, node, noFilemodeChecks);
223223
}
224224

225+
bool OrbisFSImage::checkBlockAllocations(){
226+
OrbisFSBlockAllocator va(this, _superblock->blockAllocatorLnk.blk, true);
227+
228+
va.freeBlock(_superblock->blockAllocatorLnk.blk);
229+
va.freeBlock(_superblock->diskinfoLnk.blk);
230+
{
231+
OrbisFSAllocatorInfoElem_t *aie = (OrbisFSAllocatorInfoElem_t*)getBlock(_superblock->blockAllocatorLnk.blk);
232+
uint32_t elemsCnt = getBlocksize() / sizeof(*aie);
233+
for (int i=0; i<elemsCnt; i++) {
234+
if (aie[i].bitmapBlk.type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
235+
va.freeBlock(aie[i].bitmapBlk.blk);
236+
}
237+
}
238+
239+
auto fInodes = openFileNode(_inodeDir->findInode(kOrbisFSInodeRootDirID), true);
240+
{
241+
OrbisFSInode_t node = {};
242+
while (fInodes->read(&node, sizeof(node)) == sizeof(node)) {
243+
if (node.magic != ORBIS_FS_INODE_MAGIC) continue;
244+
245+
auto fnode = openFileNode(&node, true);
246+
247+
auto usedBlks = fnode->getAllAllocatedBlocks();
248+
for (auto b : usedBlks) {
249+
va.freeBlock(b);
250+
}
251+
}
252+
}
253+
254+
return va.getFreeBlocksNum()+1 == va.getTotalBlockNum();
255+
}
256+
225257
#pragma mark OrbisFSImage public
226258
bool OrbisFSImage::isWriteable(){
227259
return _writeable;
@@ -299,3 +331,14 @@ void OrbisFSImage::iterateOverFilesInFolder(std::string path, bool recursive, st
299331
}
300332
}while(files.size());
301333
}
334+
335+
bool OrbisFSImage::check(){
336+
info("Checking block allocations...");
337+
if (!checkBlockAllocations()) goto fail;
338+
339+
success:
340+
return true;
341+
fail:
342+
error("check failed!");
343+
return false;
344+
}

orbisFSTool/OrbisFSImage.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class OrbisFSImage{
4545
void init();
4646
uint8_t *getBlock(uint32_t blknum);
4747
std::shared_ptr<OrbisFSFile> openFileNode(OrbisFSInode_t *node, bool noFilemodeChecks = false);
48+
bool checkBlockAllocations();
4849
public:
4950
OrbisFSImage(const char *path, bool writeable, uint64_t offset = 0);
5051
~OrbisFSImage();
@@ -60,6 +61,8 @@ class OrbisFSImage{
6061

6162
void iterateOverFilesInFolder(std::string path, bool recursive, std::function<void(std::string path, OrbisFSInode_t node)> callback);
6263

64+
bool check();
65+
6366
#pragma mark files
6467
std::shared_ptr<OrbisFSFile> openFileID(uint32_t inode);
6568
std::shared_ptr<OrbisFSFile> openFilAtPath(std::string path);

orbisFSTool/main.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ static struct option longopts[] = {
3636
{ "verbose", no_argument, NULL, 'v' },
3737
{ "writeable", no_argument, NULL, 'w' },
3838

39+
{ "check", no_argument, NULL, 0 },
3940
{ "extract-resource", no_argument, NULL, 0 },
4041
{ "inode", required_argument, NULL, 0 },
4142
{ "mount", required_argument, NULL, 0 },
@@ -59,6 +60,7 @@ void cmd_help(){
5960
" -r, --recursive\t\tperform operation recursively\n"
6061
" -v, --verbose\t\t\tincrease logging output\n"
6162
" -w, --writeable\t\topen image in write mode\n"
63+
" --check\tperform some checks on the image\n"
6264
" --extract-resource\textract file resource instead of file contents\n"
6365
" --inode <num>\t\tspecify file by Inode instead of path\n"
6466
" --mount <path>\t\tpath to mount\n"
@@ -130,6 +132,7 @@ int main_r(int argc, const char * argv[]) {
130132
bool doList = false;
131133
bool doExtract = false;
132134
bool doExtractResource = false;
135+
bool doCheck = false;
133136

134137
bool dumpInode = false;
135138

@@ -139,7 +142,9 @@ int main_r(int argc, const char * argv[]) {
139142
{
140143
std::string curopt = longopts[optindex].name;
141144

142-
if (curopt == "extract-resource") {
145+
if (curopt == "check") {
146+
doCheck = true;
147+
}else if (curopt == "extract-resource"){
143148
doExtractResource = true;
144149
}else if (curopt == "inode"){
145150
iNode = atoi(optarg);
@@ -216,6 +221,12 @@ int main_r(int argc, const char * argv[]) {
216221

217222
std::shared_ptr<OrbisFSImage> img = std::make_shared<OrbisFSImage>(infile, writeable, offset);
218223

224+
if (doCheck) {
225+
info("Performing image check");
226+
retassure(img->check(), "image check failed!");
227+
info("Image check succeeded!");
228+
}
229+
219230
if (!imagePath.size() && iNode) {
220231
char buf[0x100] = {};
221232
snprintf(buf, sizeof(buf), "iNode%d",iNode);

0 commit comments

Comments
 (0)