Skip to content

Commit fb27983

Browse files
committed
WIP trying to add support for shrinking files
1 parent 5767126 commit fb27983

File tree

7 files changed

+163
-34
lines changed

7 files changed

+163
-34
lines changed

orbisFSTool/OrbisFSBlockAllocator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,7 @@ void OrbisFSBlockAllocator::freeBlock(uint32_t blkNum){
108108
}
109109
reterror("failed to find block in bitmap");
110110
}
111+
112+
uint32_t OrbisFSBlockAllocator::allocateBlock(){
113+
reterror("TODO");
114+
}

orbisFSTool/OrbisFSBlockAllocator.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class OrbisFSBlockAllocator {
3636
uint64_t getFreeBlocksNum();
3737
bool isBlockFree(uint32_t blkNum);
3838
void freeBlock(uint32_t blkNum);
39+
uint32_t allocateBlock();
3940
};
4041

4142
}

orbisFSTool/OrbisFSFile.cpp

Lines changed: 130 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -57,31 +57,28 @@ uint8_t *OrbisFSFile::getDataBlock(uint64_t num){
5757
retassure(_node->dataLnk[num].type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad dataLnk type 0x%02x",_node->dataLnk[num].type);
5858
return _parent->getBlock(_node->dataLnk[num].blk);
5959
}
60-
61-
/*
62-
Multistage lookup here
63-
*/
64-
OrbisFSChainLink_t *fat = (OrbisFSChainLink_t*)_parent->getBlock(_node->dataLnk[0].blk);
65-
if (_node->fatStages >= 3) {
66-
retassure(_node->fatStages < 4, "4 level stage lookup not supported");
67-
/*
68-
Stage 3 lookup
69-
*/
70-
uint64_t stage3Idx = num / linkElemsPerPage;
71-
retassure(stage3Idx < linkElemsPerPage, "Trying to access out of bounds block on stage 3 lookup");
72-
num %= linkElemsPerPage;
73-
fat = &fat[stage3Idx];
74-
retassure(fat->type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad dataLnk type 0x%02x in stage 3 lookup",fat->type);
75-
fat = (OrbisFSChainLink_t*)_parent->getBlock(fat->blk);
76-
}
7760

78-
/*
79-
Stage 2 lookup
80-
*/
81-
retassure(num < linkElemsPerPage, "Trying to access out of bounds block on stage 3 lookup");
82-
fat = &fat[num];
83-
retassure(fat->type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad fat type 0x%02x",fat->type);
84-
return _parent->getBlock(fat->blk);
61+
OrbisFSChainLink_t *fat = NULL;
62+
for (int i=_node->fatStages-1; i>=0; i--) {
63+
uint64_t elemsInThisStage = 1;
64+
for (int z=0; z<i; z++) elemsInThisStage *= linkElemsPerPage;
65+
uint32_t curIdx = (uint32_t)(num / elemsInThisStage);
66+
num %= elemsInThisStage;
67+
68+
if (!fat) {
69+
//this is the first level lookup
70+
retassure(curIdx < ARRAYOF(_node->dataLnk), "1 level lookup out of bounds");
71+
retassure(_node->dataLnk[curIdx].type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad dataLnk type 0x%02x",_node->dataLnk[curIdx].type);
72+
fat = (OrbisFSChainLink_t*)_parent->getBlock(_node->dataLnk[curIdx].blk);
73+
}else{
74+
//this is further level lookup
75+
retassure(curIdx < linkElemsPerPage, "Trying to access out of bounds block on stage %d lookup",_node->fatStages-(i-1));
76+
fat = &fat[curIdx];
77+
retassure(fat->type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad fat type 0x%02x",fat->type);
78+
fat = (OrbisFSChainLink_t*)_parent->getBlock(fat->blk);
79+
}
80+
}
81+
return (uint8_t*)fat;
8582
}
8683

8784
uint8_t *OrbisFSFile::getDataForOffset(uint64_t offset){
@@ -105,14 +102,8 @@ std::vector<uint32_t> OrbisFSFile::getAllAllocatedBlocks(){
105102
ret.push_back(_node->dataLnk[i].blk);
106103
}
107104
}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-
}
105+
reterror("TODO");
106+
116107
}else if (_node->fatStages == 3){
117108

118109
reterror("TODO");
@@ -129,6 +120,105 @@ std::vector<uint32_t> OrbisFSFile::getAllAllocatedBlocks(){
129120
return ret;
130121
}
131122

123+
void OrbisFSFile::popLastAllocatedBlock(){
124+
const uint32_t linkElemsPerPage = _blockSize/sizeof(OrbisFSChainLink_t);
125+
OrbisFSChainLink_t *tgt = NULL;
126+
uint32_t curIdx = 0;
127+
int fatEndStage = 0;
128+
uint32_t usedResourceBlocks = 0;
129+
130+
for (int i=0; i<ARRAYOF(_node->resourceLnk); i++) {
131+
if (_node->resourceLnk[i].type != ORBIS_FS_CHAINLINK_TYPE_LINK) break;
132+
usedResourceBlocks++;
133+
}
134+
135+
if (!_node->fatStages){
136+
reterror("No stages available");
137+
}else if (_node->fatStages == 1) {
138+
for (int i=ARRAYOF(_node->dataLnk)-1; i>=0; i--) {
139+
if (_node->dataLnk[i].type == ORBIS_FS_CHAINLINK_TYPE_LINK){
140+
tgt = &_node->dataLnk[i];
141+
if (i==0) _node->fatStages = 0;
142+
break;
143+
}
144+
}
145+
}else{
146+
rePopBlock:
147+
retassure(_node->usedBlocks, "Why does this node not use any blocks??");
148+
uint64_t num = _node->filesize / _blockSize;
149+
if ((_node->filesize & (_blockSize-1)) == 0) num--; //num is actually blockIndex not blockNumber
150+
151+
OrbisFSChainLink_t *fat = NULL;
152+
for (int i=_node->fatStages-1; i>=fatEndStage; i--) {
153+
uint64_t elemsInThisStage = 1;
154+
for (int z=0; z<i; z++) elemsInThisStage *= linkElemsPerPage;
155+
curIdx = (uint32_t)(num / elemsInThisStage);
156+
num %= elemsInThisStage;
157+
158+
if (!fat) {
159+
//this is the first level lookup
160+
retassure(curIdx < ARRAYOF(_node->dataLnk), "1 level lookup out of bounds");
161+
tgt = &_node->dataLnk[curIdx];
162+
retassure(tgt->type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad dataLnk type 0x%02x",tgt->type);
163+
fat = (OrbisFSChainLink_t*)_parent->getBlock(tgt->blk);
164+
}else{
165+
//this is further level lookup
166+
retassure(curIdx < linkElemsPerPage, "Trying to access out of bounds block on stage %d lookup",_node->fatStages-(i-1));
167+
tgt = &fat[curIdx];
168+
retassure(tgt->type == ORBIS_FS_CHAINLINK_TYPE_LINK, "bad fat type 0x%02x",tgt->type);
169+
fat = (OrbisFSChainLink_t*)_parent->getBlock(tgt->blk);
170+
}
171+
}
172+
}
173+
174+
retassure(_node->fatStages < 4, "4 level stages currently not supported!");
175+
176+
{
177+
uint32_t blk = tgt->blk;
178+
memset(tgt, 0xFF, sizeof(*tgt));
179+
_parent->freeBlock(blk);
180+
_node->usedBlocks--;
181+
if (curIdx == 0 && (_node->fatStages-fatEndStage > 1)) {
182+
fatEndStage++;
183+
goto rePopBlock;
184+
} else if (curIdx == 1 && (
185+
(_node->fatStages == 2 && _node->usedBlocks == 2+usedResourceBlocks)
186+
|| (_node->fatStages == 3 && _node->usedBlocks == linkElemsPerPage+2+usedResourceBlocks)
187+
)){
188+
/*
189+
We are at fatStages>=2 but we can downgrage to fatStages>=1 here
190+
*/
191+
retassure(_node->dataLnk[0].type == ORBIS_FS_CHAINLINK_TYPE_LINK, "unexpecte invalid dataLnk[0] when attepmting to downgrade fatStages 2 -> 1");
192+
blk = _node->dataLnk[0].blk;
193+
tgt = (OrbisFSChainLink_t*)_parent->getBlock(blk);
194+
retassure(tgt->type == ORBIS_FS_CHAINLINK_TYPE_LINK, "unexpecte invalid tgt when attepmting to downgrade fatStages 2 -> 1");
195+
_node->dataLnk[0] = *tgt;
196+
_parent->freeBlock(blk);
197+
_node->usedBlocks--;
198+
_node->fatStages--;
199+
}
200+
}
201+
}
202+
203+
void OrbisFSFile::shrink(uint64_t subBytes){
204+
retassure(_node->filesize >= subBytes, "trying to shrink more bytes than available");
205+
while (subBytes) {
206+
uint64_t lastBlockFill = _node->filesize & (_blockSize-1);
207+
if (!lastBlockFill && _node->filesize >= _blockSize) lastBlockFill = _blockSize;
208+
if (subBytes >= lastBlockFill) {
209+
popLastAllocatedBlock();
210+
}else{
211+
lastBlockFill = subBytes;
212+
}
213+
_node->filesize -= lastBlockFill;
214+
subBytes -= lastBlockFill;
215+
}
216+
}
217+
218+
void OrbisFSFile::grow(uint64_t addBytes){
219+
reterror("TODO");
220+
}
221+
132222
#pragma mark OrbisFSFile public
133223
#pragma mark IO operations
134224
uint64_t OrbisFSFile::size(){
@@ -165,6 +255,14 @@ size_t OrbisFSFile::pwrite(const void *buf, size_t len, uint64_t offset){
165255
reterror("TODO");
166256
}
167257

258+
void OrbisFSFile::resize(uint64_t size){
259+
if (size < _node->filesize) {
260+
shrink(_node->filesize-size);
261+
}else if (size > _node->filesize){
262+
grow(size-_node->filesize);
263+
}
264+
}
265+
168266
#pragma mark resource IO
169267
uint64_t OrbisFSFile::resource_size(){
170268
/*

orbisFSTool/OrbisFSFile.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ class OrbisFSFile {
3030
uint8_t *getDataBlock(uint64_t num);
3131
uint8_t *getDataForOffset(uint64_t offset);
3232
std::vector<uint32_t> getAllAllocatedBlocks();
33+
void popLastAllocatedBlock();
34+
void shrink(uint64_t subBytes);
35+
void grow(uint64_t addBytes);
3336
public:
3437
OrbisFSFile(OrbisFSImage *parent, OrbisFSInode_t *node, bool noFilemodeChecks = false);
3538
~OrbisFSFile();
@@ -42,6 +45,8 @@ class OrbisFSFile {
4245
size_t pread(void *buf, size_t len, uint64_t offset);
4346
size_t pwrite(const void *buf, size_t len, uint64_t offset);
4447

48+
void resize(uint64_t size);
49+
4550
#pragma mark resource IO
4651
uint64_t resource_size();
4752
size_t resource_pread(void *buf, size_t len, uint64_t offset);

orbisFSTool/OrbisFSImage.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ OrbisFSImage::OrbisFSImage(const char *path, bool writeable, uint64_t offset)
4343
, _inodeDir(nullptr)
4444
, _references(0)
4545
{
46+
#ifndef DEBUG
47+
retassure(!_writeable, "Experimental write support is only available in DEBUG builds!");
48+
#endif
49+
4650
retassure((_fd = open(path, writeable ? O_RDWR : O_RDONLY)) != -1, "Failed to open=%s",path);
4751
{
4852
struct stat st = {};
@@ -84,7 +88,7 @@ OrbisFSImage::OrbisFSImage(const char *path, bool writeable, uint64_t offset)
8488
retassure(_memsize, "Failed to detect image size!");
8589
retassure(_memsize > offset, "offset beyond image size");
8690
_memsize -= offset;
87-
if ((_mem = (uint8_t*)mmap(NULL, _memsize, PROT_READ | (writeable ? PROT_WRITE : 0), MAP_FILE | (writeable ? MAP_SHARED : MAP_PRIVATE), _fd, offset)) == MAP_FAILED){
91+
if ((_mem = (uint8_t*)mmap(NULL, _memsize, PROT_READ | PROT_WRITE, MAP_FILE | (writeable ? MAP_SHARED : MAP_PRIVATE), _fd, offset)) == MAP_FAILED){
8892
reterror("Failed to mmap '%s' errno=%d (%s)",path,errno,strerror(errno));
8993
}
9094
init();
@@ -254,6 +258,11 @@ bool OrbisFSImage::checkBlockAllocations(){
254258
return va.getFreeBlocksNum()+1 == va.getTotalBlockNum();
255259
}
256260

261+
void OrbisFSImage::freeBlock(uint32_t blk){
262+
_blockAllocator->freeBlock(blk);
263+
_diskinfoblock->blocksUsed--;
264+
}
265+
257266
#pragma mark OrbisFSImage public
258267
bool OrbisFSImage::isWriteable(){
259268
return _writeable;

orbisFSTool/OrbisFSImage.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class OrbisFSImage{
4646
uint8_t *getBlock(uint32_t blknum);
4747
std::shared_ptr<OrbisFSFile> openFileNode(OrbisFSInode_t *node, bool noFilemodeChecks = false);
4848
bool checkBlockAllocations();
49+
void freeBlock(uint32_t blk);
4950
public:
5051
OrbisFSImage(const char *path, bool writeable, uint64_t offset = 0);
5152
~OrbisFSImage();

orbisFSTool/main.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ static struct option longopts[] = {
4141
{ "inode", required_argument, NULL, 0 },
4242
{ "mount", required_argument, NULL, 0 },
4343
{ "offset", required_argument, NULL, 0 },
44+
{ "resize-file", required_argument, NULL, 0 },
4445

4546
//advanced debugging
4647
{ "dump-inode", no_argument, NULL, 0 },
@@ -65,6 +66,7 @@ void cmd_help(){
6566
" --inode <num>\t\tspecify file by Inode instead of path\n"
6667
" --mount <path>\t\tpath to mount\n"
6768
" --offset <cnt>\t\toffset inside image\n"
69+
" --resize-file <size>\t\tresize file inside image\n"
6870
"\n"
6971
//advanced debugging
7072
" --dump-inode\t\tdump inode structure\n"
@@ -122,6 +124,7 @@ int main_r(int argc, const char * argv[]) {
122124
std::string imagePath;
123125

124126
uint64_t offset = 0;
127+
uint64_t newFileSize = 0;
125128
uint32_t iNode = 0;
126129

127130
int verbosity = 0;
@@ -133,10 +136,11 @@ int main_r(int argc, const char * argv[]) {
133136
bool doExtract = false;
134137
bool doExtractResource = false;
135138
bool doCheck = false;
139+
bool doResizeFile = false;
136140

137141
bool dumpInode = false;
138142

139-
while ((opt = getopt_long(argc, (char* const *)argv, "he::i:l::o:rvw", longopts, &optindex)) >= 0) {
143+
while ((opt = getopt_long(argc, (char* const *)argv, "he::i:l::o:p:rvw", longopts, &optindex)) >= 0) {
140144
switch (opt) {
141145
case 0: //long opts
142146
{
@@ -152,6 +156,9 @@ int main_r(int argc, const char * argv[]) {
152156
mountPath = optarg;
153157
}else if (curopt == "offset"){
154158
offset = parseNum(optarg);
159+
}else if (curopt == "resize-file"){
160+
doResizeFile = true;
161+
newFileSize = parseNum(optarg);
155162

156163
}else if (curopt == "dump-inode"){
157164
dumpInode = true;
@@ -363,6 +370,10 @@ int main_r(int argc, const char * argv[]) {
363370
}
364371
}
365372
});
373+
}else if (doResizeFile) {
374+
retassure(imagePath.size(), "No path for resize specified");
375+
auto f = img->openFilAtPath(imagePath);
376+
f->resize(newFileSize);
366377
}else if (mountPath) {
367378
info("Mounting disk");
368379
OrbisFSFuse off(img, mountPath);

0 commit comments

Comments
 (0)