21 #include "Ext2Filesystem.h" 23 #include "modules/system/vfs/File.h" 24 #include "pedigree/kernel/Log.h" 25 #include "pedigree/kernel/compiler.h" 26 #include "pedigree/kernel/syscallError.h" 27 #include "pedigree/kernel/utilities/assert.h" 28 #include "pedigree/kernel/utilities/utility.h" 31 : m_pInode(pInode), m_InodeNumber(inode_num), m_pExt2Fs(pFs), m_Blocks(),
32 m_nMetadataBlocks(0), m_nSize(LITTLE_TO_HOST32(pInode->i_size))
35 uint32_t blockCount = LITTLE_TO_HOST32(pInode->i_blocks);
36 uint32_t totalBlocks = (blockCount * 512) / m_pExt2Fs->
m_BlockSize;
38 size_t dataBlockCount = m_nSize / m_pExt2Fs->
m_BlockSize;
44 m_Blocks.
reserve(dataBlockCount,
false);
45 m_nMetadataBlocks = totalBlocks - dataBlockCount;
47 for (
size_t i = 0; i < 12 && i < dataBlockCount; i++)
48 m_Blocks.
pushBack(LITTLE_TO_HOST32(m_pInode->i_block[i]));
51 for (
size_t i = 12; i < dataBlockCount; ++i)
61 uintptr_t Ext2Node::readBlock(uint64_t location)
64 uint32_t nBlock = location / m_pExt2Fs->
m_BlockSize;
65 if (nBlock > m_Blocks.
count())
68 "Ext2Node::readBlock beyond blocks [" << nBlock <<
", " 69 << m_Blocks.
count() <<
"]");
72 if (location > m_nSize)
75 "Ext2Node::readBlock beyond size [" << location <<
", " << m_nSize
80 ensureBlockLoaded(nBlock);
81 uintptr_t result = m_pExt2Fs->
readBlock(m_Blocks[nBlock]);
88 void Ext2Node::writeBlock(uint64_t location)
91 uint32_t nBlock = location / m_pExt2Fs->
m_BlockSize;
92 if (nBlock > m_Blocks.
count())
94 if (location > m_nSize)
98 ensureBlockLoaded(nBlock);
102 void Ext2Node::trackBlock(uint32_t block)
109 m_pInode->i_blocks = HOST_TO_LITTLE32(i_blocks);
112 m_pExt2Fs->writeInode(getInodeNumber());
117 for (
size_t i = 0; i < m_Blocks.
count(); ++i)
119 ensureBlockLoaded(i);
126 m_pInode->i_size = 0;
127 m_pInode->i_blocks = 0;
128 ByteSet(m_pInode->i_block, 0,
sizeof(uint32_t) * 15);
131 m_pExt2Fs->writeInode(getInodeNumber());
134 void Ext2Node::extend(
size_t newSize)
139 void Ext2Node::extend(
size_t newSize, uint64_t location, uint64_t size)
150 size_t currentMaxSize = m_Blocks.
count() * blockSize;
151 if (
LIKELY(size <= currentMaxSize))
153 if (size > m_nSize && !onlyBlocks)
158 m_nSize, LITTLE_TO_HOST32(m_pInode->i_atime),
159 LITTLE_TO_HOST32(m_pInode->i_mtime),
160 LITTLE_TO_HOST32(m_pInode->i_ctime));
164 else if (!onlyBlocks)
168 m_nSize, LITTLE_TO_HOST32(m_pInode->i_atime),
169 LITTLE_TO_HOST32(m_pInode->i_mtime),
170 LITTLE_TO_HOST32(m_pInode->i_ctime));
173 size_t delta = size - currentMaxSize;
174 size_t deltaBlocks = delta / blockSize;
175 if (delta % blockSize)
183 if (!m_pExt2Fs->
findFreeBlocks(m_InodeNumber, deltaBlocks, newBlocks))
185 SYSCALL_ERROR(NoSpaceLeftOnDevice);
189 for (
size_t i = 0; i < deltaBlocks; ++i)
191 uint32_t block = m_pExt2Fs->findFreeBlock(m_InodeNumber);
194 SYSCALL_ERROR(NoSpaceLeftOnDevice);
204 for (
auto block : newBlocks)
206 if (!addBlock(block))
208 ERROR(
"Adding block " << block <<
" failed!");
214 reinterpret_cast<uint8_t *
>(m_pExt2Fs->
readBlock(block));
217 bool zero = !nozeroblocks;
218 if (location || opsize)
220 uint64_t offset = block * blockSize;
221 if (offset >= location)
224 size_t end = (block + 1) * blockSize;
226 if (end <= (location + opsize))
242 bool Ext2Node::ensureBlockLoaded(
size_t nBlock)
244 if (nBlock > m_Blocks.
count())
247 "EXT2: ensureBlockLoaded: Algorithmic error [block " 248 << nBlock <<
" > " << m_Blocks.
count() <<
"].");
250 if (m_Blocks[nBlock] == ~0U)
251 getBlockNumber(nBlock);
256 bool Ext2Node::getBlockNumber(
size_t nBlock)
262 if (nBlock < nPerBlock + 12)
264 getBlockNumberIndirect(
265 LITTLE_TO_HOST32(m_pInode->i_block[12]), 12, nBlock);
269 if (nBlock < (nPerBlock * nPerBlock) + nPerBlock + 12)
271 getBlockNumberBiindirect(
272 LITTLE_TO_HOST32(m_pInode->i_block[13]), nPerBlock + 12, nBlock);
276 getBlockNumberTriindirect(
277 LITTLE_TO_HOST32(m_pInode->i_block[14]),
278 (nPerBlock * nPerBlock) + nPerBlock + 12, nBlock);
283 bool Ext2Node::getBlockNumberIndirect(
284 uint32_t inode_block,
size_t nBlocks,
size_t nBlock)
287 reinterpret_cast<uint32_t *
>(m_pExt2Fs->
readBlock(inode_block));
292 m_Blocks[nBlocks++] = LITTLE_TO_HOST32(buffer[i]);
298 bool Ext2Node::getBlockNumberBiindirect(
299 uint32_t inode_block,
size_t nBlocks,
size_t nBlock)
304 reinterpret_cast<uint32_t *
>(m_pExt2Fs->
readBlock(inode_block));
307 size_t nIndirectBlock = (nBlock - nBlocks) / nPerBlock;
309 getBlockNumberIndirect(
310 LITTLE_TO_HOST32(buffer[nIndirectBlock]),
311 nBlocks + nIndirectBlock * nPerBlock, nBlock);
316 bool Ext2Node::getBlockNumberTriindirect(
317 uint32_t inode_block,
size_t nBlocks,
size_t nBlock)
322 reinterpret_cast<uint32_t *
>(m_pExt2Fs->
readBlock(inode_block));
325 size_t nBiBlock = (nBlock - nBlocks) / (nPerBlock * nPerBlock);
327 getBlockNumberBiindirect(
328 LITTLE_TO_HOST32(buffer[nBiBlock]),
329 nBlocks + nBiBlock * nPerBlock * nPerBlock, nBlock);
334 bool Ext2Node::addBlock(uint32_t blockValue)
336 size_t nEntriesPerBlock = m_pExt2Fs->
m_BlockSize / 4;
339 if (m_Blocks.
count() < 12)
342 m_pInode->i_block[m_Blocks.
count()] = HOST_TO_LITTLE32(blockValue);
344 else if (m_Blocks.
count() < 12 + nEntriesPerBlock)
347 size_t indirectIdx = m_Blocks.
count() - 12;
351 if (m_Blocks.
count() == 12)
353 uint32_t newBlock = m_pExt2Fs->findFreeBlock(m_InodeNumber);
354 m_pInode->i_block[12] = HOST_TO_LITTLE32(newBlock);
355 if (m_pInode->i_block[12] == 0)
358 SYSCALL_ERROR(NoSpaceLeftOnDevice);
363 reinterpret_cast<void *
>(m_pExt2Fs->
readBlock(newBlock));
375 uint32_t bufferBlock = LITTLE_TO_HOST32(m_pInode->i_block[12]);
377 reinterpret_cast<uint32_t *
>(m_pExt2Fs->
readBlock(bufferBlock));
379 buffer[indirectIdx] = HOST_TO_LITTLE32(blockValue);
384 12 + nEntriesPerBlock + nEntriesPerBlock * nEntriesPerBlock)
390 size_t biIdx = m_Blocks.
count() - 12 - nEntriesPerBlock;
393 size_t indirectBlock = biIdx / nEntriesPerBlock;
395 size_t indirectIdx = biIdx % nEntriesPerBlock;
401 uint32_t newBlock = m_pExt2Fs->findFreeBlock(m_InodeNumber);
402 m_pInode->i_block[13] = HOST_TO_LITTLE32(newBlock);
403 if (m_pInode->i_block[13] == 0)
406 SYSCALL_ERROR(NoSpaceLeftOnDevice);
411 reinterpret_cast<void *
>(m_pExt2Fs->
readBlock(newBlock));
420 uint32_t bufferBlock = LITTLE_TO_HOST32(m_pInode->i_block[13]);
422 reinterpret_cast<uint32_t *
>(m_pExt2Fs->
readBlock(bufferBlock));
425 if (indirectIdx == 0)
427 uint32_t newBlock = m_pExt2Fs->findFreeBlock(m_InodeNumber);
428 pBlock[indirectBlock] = HOST_TO_LITTLE32(newBlock);
429 if (pBlock[indirectBlock] == 0)
432 SYSCALL_ERROR(NoSpaceLeftOnDevice);
439 reinterpret_cast<void *
>(m_pExt2Fs->
readBlock(newBlock));
449 uint32_t nIndirectBlockNum = LITTLE_TO_HOST32(pBlock[indirectBlock]);
452 pBlock =
reinterpret_cast<uint32_t *
>(
453 m_pExt2Fs->
readBlock(nIndirectBlockNum));
454 if (pBlock == reinterpret_cast<uint32_t *>(~0))
457 "Could not read block (" << nIndirectBlockNum
458 <<
") that we wanted to add.");
463 pBlock[indirectIdx] = HOST_TO_LITTLE32(blockValue);
469 FATAL(
"EXT2: Tri-indirect addressing required, but not implemented.");
473 trackBlock(blockValue);
479 size_t size,
size_t atime,
size_t mtime,
size_t ctime)
484 m_pInode->i_blocks = HOST_TO_LITTLE32(i_blocks);
485 m_pInode->i_size = HOST_TO_LITTLE32(size);
486 m_pInode->i_atime = HOST_TO_LITTLE32(atime);
487 m_pInode->i_mtime = HOST_TO_LITTLE32(mtime);
488 m_pInode->i_ctime = HOST_TO_LITTLE32(ctime);
494 m_pExt2Fs->writeInode(getInodeNumber());
500 uint32_t curr_mode = LITTLE_TO_HOST32(m_pInode->i_mode);
501 curr_mode &= ~((1 << 9) - 1);
504 m_pInode->i_uid = HOST_TO_LITTLE16(uid);
505 m_pInode->i_gid = HOST_TO_LITTLE16(gid);
506 m_pInode->i_mode = HOST_TO_LITTLE32(curr_mode);
509 m_pExt2Fs->writeInode(getInodeNumber());
512 void Ext2Node::sync(
size_t offset,
bool async)
515 if (nBlock > m_Blocks.
count())
517 if (offset > m_nSize)
521 ensureBlockLoaded(nBlock);
522 m_pExt2Fs->sync(m_Blocks[nBlock] * m_pExt2Fs->
m_BlockSize, async);
525 void Ext2Node::pinBlock(uint64_t location)
527 uint32_t nBlock = location / m_pExt2Fs->
m_BlockSize;
528 if (nBlock > m_Blocks.
count())
530 if (location > m_nSize)
533 ensureBlockLoaded(nBlock);
534 m_pExt2Fs->pinBlock(m_Blocks[nBlock]);
537 void Ext2Node::unpinBlock(uint64_t location)
539 uint32_t nBlock = location / m_pExt2Fs->
m_BlockSize;
540 if (nBlock > m_Blocks.
count())
542 if (location > m_nSize)
545 ensureBlockLoaded(nBlock);
546 m_pExt2Fs->unpinBlock(m_Blocks[nBlock]);
549 uint32_t Ext2Node::modeToPermissions(uint32_t mode)
const 551 uint32_t permissions = 0;
552 if (mode & EXT2_S_IRUSR)
553 permissions |= FILE_UR;
554 if (mode & EXT2_S_IWUSR)
555 permissions |= FILE_UW;
556 if (mode & EXT2_S_IXUSR)
557 permissions |= FILE_UX;
558 if (mode & EXT2_S_IRGRP)
559 permissions |= FILE_GR;
560 if (mode & EXT2_S_IWGRP)
561 permissions |= FILE_GW;
562 if (mode & EXT2_S_IXGRP)
563 permissions |= FILE_GX;
564 if (mode & EXT2_S_IROTH)
565 permissions |= FILE_OR;
566 if (mode & EXT2_S_IWOTH)
567 permissions |= FILE_OW;
568 if (mode & EXT2_S_IXOTH)
569 permissions |= FILE_OX;
573 uint32_t Ext2Node::permissionsToMode(uint32_t permissions)
const 576 if (permissions & FILE_UR)
577 mode |= EXT2_S_IRUSR;
578 if (permissions & FILE_UW)
579 mode |= EXT2_S_IWUSR;
580 if (permissions & FILE_UX)
581 mode |= EXT2_S_IXUSR;
582 if (permissions & FILE_GR)
583 mode |= EXT2_S_IRGRP;
584 if (permissions & FILE_GW)
585 mode |= EXT2_S_IWGRP;
586 if (permissions & FILE_GX)
587 mode |= EXT2_S_IXGRP;
588 if (permissions & FILE_OR)
589 mode |= EXT2_S_IROTH;
590 if (permissions & FILE_OW)
591 mode |= EXT2_S_IWOTH;
592 if (permissions & FILE_OX)
593 mode |= EXT2_S_IXOTH;
void pushBack(const T &value)
Ext2Node(const Ext2Node &file)
void releaseBlock(uint32_t block)
void updateMetadata(uint16_t uid, uint16_t gid, uint32_t perms)
bool ensureLargeEnough(size_t size, uint64_t location, uint64_t opsize, bool onlyBlocks=false, bool nozeroblocks=false)
void fileAttributeChanged(size_t size, size_t atime, size_t mtime, size_t ctime)
bool findFreeBlocks(uint32_t inode, size_t count, Vector< uint32_t > &blocks)
void reserve(size_t size, bool copy)
uintptr_t readBlock(uint32_t block)
void clear(bool freeMem=false)
void writeBlock(uint32_t block)