* added support for huge_file feature, untested (need a >2TB file)
* actually checks for readonly features if mounting read-write * don't use a journal when mounting readonly * DataStream::_BlocksNeeded(): in case of double or triple indirects, compute the additional blocks needed using the difference between the old and new indirects blocks. This was resulting in a bad NumBlocks on an inode * BitmapBlock: mark methods missed an iteration when the startingBit was zero. Some blocks were then allocated two times (at most 32 for each allocation run). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38950 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -94,7 +94,8 @@ BitmapBlock::CheckUnmarked(uint32 start, uint32 length)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
} else
|
||||||
|
iterations++;
|
||||||
|
|
||||||
for (; iterations > 0; --iterations) {
|
for (; iterations > 0; --iterations) {
|
||||||
if (data[index++] != 0)
|
if (data[index++] != 0)
|
||||||
@@ -153,7 +154,8 @@ BitmapBlock::CheckMarked(uint32 start, uint32 length)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
} else
|
||||||
|
iterations++;
|
||||||
|
|
||||||
mask = 0xFFFFFFFF;
|
mask = 0xFFFFFFFF;
|
||||||
for (; iterations > 0; --iterations) {
|
for (; iterations > 0; --iterations) {
|
||||||
@@ -216,7 +218,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
|
|||||||
mask = ~((1 << startBit) - 1);
|
mask = ~((1 << startBit) - 1);
|
||||||
uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
|
uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
|
||||||
|
|
||||||
TRACE("BitmapBlock::Mark(): mask: %lX, bits: %lX\n", mask, bits);
|
TRACE("BitmapBlock::Mark(): index %lu mask: %lX, bits: %lX\n", index,
|
||||||
|
mask, bits);
|
||||||
|
|
||||||
if (!force && (bits & mask) != 0)
|
if (!force && (bits & mask) != 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -225,7 +228,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
|
|||||||
fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
|
fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
|
||||||
|
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
} else
|
||||||
|
iterations++;
|
||||||
|
|
||||||
mask = 0xFFFFFFFF;
|
mask = 0xFFFFFFFF;
|
||||||
for (; iterations > 0; --iterations) {
|
for (; iterations > 0; --iterations) {
|
||||||
@@ -237,8 +241,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
|
|||||||
if (remainingBits != 0) {
|
if (remainingBits != 0) {
|
||||||
mask = (1 << remainingBits) - 1;
|
mask = (1 << remainingBits) - 1;
|
||||||
uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
|
uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
|
||||||
TRACE("BitmapBlock::(): marking remaining %lu bits: %lX, mask: %lX\n",
|
TRACE("BitmapBlock::Mark(): marking index %lu remaining %lu bits: %lX,"
|
||||||
remainingBits, bits, mask);
|
" mask: %lX\n", index, remainingBits, bits, mask);
|
||||||
|
|
||||||
if (!force && (bits & mask) != 0)
|
if (!force && (bits & mask) != 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -310,7 +314,8 @@ BitmapBlock::Unmark(uint32 start, uint32 length, bool force)
|
|||||||
|
|
||||||
TRACE("BitmapBlock::Unmark(): updated bits: %lx\n", bits);
|
TRACE("BitmapBlock::Unmark(): updated bits: %lx\n", bits);
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
} else
|
||||||
|
iterations++;
|
||||||
|
|
||||||
mask = 0xFFFFFFFF;
|
mask = 0xFFFFFFFF;
|
||||||
for (; iterations > 0; --iterations) {
|
for (; iterations > 0; --iterations) {
|
||||||
@@ -656,9 +661,3 @@ BitmapBlock::FindLargestUnmarkedRange(uint32& start, uint32& length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32
|
|
||||||
BitmapBlock::NumBits() const
|
|
||||||
{
|
|
||||||
return fNumBits;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public:
|
|||||||
void FindLargestUnmarkedRange(uint32& start,
|
void FindLargestUnmarkedRange(uint32& start,
|
||||||
uint32& length);
|
uint32& length);
|
||||||
|
|
||||||
uint32 NumBits() const;
|
uint32 NumBits() const { return fNumBits; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32* fData;
|
uint32* fData;
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ status_t
|
|||||||
AllocationBlockGroup::Allocate(Transaction& transaction, uint32 start,
|
AllocationBlockGroup::Allocate(Transaction& transaction, uint32 start,
|
||||||
uint32 length)
|
uint32 length)
|
||||||
{
|
{
|
||||||
TRACE("AllocationBlockGroup::Allocate()\n");
|
TRACE("AllocationBlockGroup::Allocate(%ld,%ld)\n", start, length);
|
||||||
uint32 end = start + length;
|
uint32 end = start + length;
|
||||||
if (end > fNumBits)
|
if (end > fNumBits)
|
||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
@@ -463,7 +463,7 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
|
|||||||
{
|
{
|
||||||
TRACE("BlockAllocator::AllocateBlocks()\n");
|
TRACE("BlockAllocator::AllocateBlocks()\n");
|
||||||
MutexLocker lock(fLock);
|
MutexLocker lock(fLock);
|
||||||
TRACE("BlockAllocator::AllocateBlocks(): Aquired lock\n");
|
TRACE("BlockAllocator::AllocateBlocks(): Acquired lock\n");
|
||||||
|
|
||||||
TRACE("BlockAllocator::AllocateBlocks(): transaction: %ld, min: %lu, "
|
TRACE("BlockAllocator::AllocateBlocks(): transaction: %ld, min: %lu, "
|
||||||
"max: %lu, block group: %lu, start: %lu, num groups: %lu\n",
|
"max: %lu, block group: %lu, start: %lu, num groups: %lu\n",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ DataStream::DataStream(Volume* volume, ext2_data_stream* stream,
|
|||||||
off_t size)
|
off_t size)
|
||||||
:
|
:
|
||||||
kBlockSize(volume->BlockSize()),
|
kBlockSize(volume->BlockSize()),
|
||||||
kIndirectsPerBlock(kBlockSize / 4),
|
kIndirectsPerBlock(kBlockSize / sizeof(uint32)),
|
||||||
kIndirectsPerBlock2(kIndirectsPerBlock * kIndirectsPerBlock),
|
kIndirectsPerBlock2(kIndirectsPerBlock * kIndirectsPerBlock),
|
||||||
kIndirectsPerBlock3(kIndirectsPerBlock2 * kIndirectsPerBlock),
|
kIndirectsPerBlock3(kIndirectsPerBlock2 * kIndirectsPerBlock),
|
||||||
kMaxDirect(EXT2_DIRECT_BLOCKS),
|
kMaxDirect(EXT2_DIRECT_BLOCKS),
|
||||||
@@ -195,20 +195,9 @@ DataStream::_BlocksNeeded(uint32 numBlocks)
|
|||||||
blocksNeeded += 2 + (numBlocks - kMaxIndirect - 1)
|
blocksNeeded += 2 + (numBlocks - kMaxIndirect - 1)
|
||||||
/ kIndirectsPerBlock;
|
/ kIndirectsPerBlock;
|
||||||
} else {
|
} else {
|
||||||
blocksNeeded += (numBlocks - fNumBlocks)
|
blocksNeeded += (numBlocks - kMaxIndirect - 1)
|
||||||
/ kIndirectsPerBlock;
|
/ kIndirectsPerBlock - (fNumBlocks
|
||||||
|
- kMaxIndirect - 1) / kIndirectsPerBlock;
|
||||||
uint32 halfIndirectsPerBlock = kIndirectsPerBlock / 2;
|
|
||||||
uint32 remCurrent = (fNumBlocks - kMaxIndirect - 1)
|
|
||||||
% kIndirectsPerBlock;
|
|
||||||
uint32 remTarget = (numBlocks - kMaxIndirect - 1)
|
|
||||||
% kIndirectsPerBlock;
|
|
||||||
|
|
||||||
if ((remCurrent >= halfIndirectsPerBlock
|
|
||||||
&& remTarget < halfIndirectsPerBlock)
|
|
||||||
|| (remCurrent > halfIndirectsPerBlock
|
|
||||||
&& remTarget <= halfIndirectsPerBlock))
|
|
||||||
blocksNeeded++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numBlocks > kMaxDoubleIndirect) {
|
if (numBlocks > kMaxDoubleIndirect) {
|
||||||
@@ -216,21 +205,9 @@ DataStream::_BlocksNeeded(uint32 numBlocks)
|
|||||||
blocksNeeded += 2 + (numBlocks - kMaxDoubleIndirect - 1)
|
blocksNeeded += 2 + (numBlocks - kMaxDoubleIndirect - 1)
|
||||||
/ kIndirectsPerBlock2;
|
/ kIndirectsPerBlock2;
|
||||||
} else {
|
} else {
|
||||||
blocksNeeded += (numBlocks - fNumBlocks)
|
blocksNeeded += (numBlocks - kMaxDoubleIndirect - 1)
|
||||||
/ kIndirectsPerBlock2;
|
/ kIndirectsPerBlock - (fNumBlocks
|
||||||
|
- kMaxDoubleIndirect - 1) / kIndirectsPerBlock;
|
||||||
uint32 halfIndirectsPerBlock2 = kIndirectsPerBlock2 / 2;
|
|
||||||
uint32 remCurrent = (fNumBlocks - kMaxDoubleIndirect
|
|
||||||
- 1)
|
|
||||||
% kIndirectsPerBlock2;
|
|
||||||
uint32 remTarget = (numBlocks - kMaxDoubleIndirect - 1)
|
|
||||||
% kIndirectsPerBlock2;
|
|
||||||
|
|
||||||
if ((remCurrent >= halfIndirectsPerBlock2
|
|
||||||
&& remTarget < halfIndirectsPerBlock2)
|
|
||||||
|| (remCurrent > halfIndirectsPerBlock2
|
|
||||||
&& remTarget <= halfIndirectsPerBlock2))
|
|
||||||
blocksNeeded++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,6 +237,9 @@ DataStream::_GetBlock(Transaction& transaction, uint32& block)
|
|||||||
|
|
||||||
fWaiting -= fAllocated;
|
fWaiting -= fAllocated;
|
||||||
fAllocatedPos += fVolume->BlocksPerGroup() * blockGroup + fFirstBlock;
|
fAllocatedPos += fVolume->BlocksPerGroup() * blockGroup + fFirstBlock;
|
||||||
|
|
||||||
|
TRACE("DataStream::_GetBlock(): newAllocated: %lu, newpos: %lu,"
|
||||||
|
"newwaiting: %lu\n", fAllocated, fAllocatedPos, fWaiting);
|
||||||
}
|
}
|
||||||
|
|
||||||
fAllocated--;
|
fAllocated--;
|
||||||
@@ -339,7 +319,7 @@ DataStream::_AddBlocks(Transaction& transaction, uint32* block, uint32 start,
|
|||||||
else if (recursion == 2)
|
else if (recursion == 2)
|
||||||
elementWidth = kIndirectsPerBlock2;
|
elementWidth = kIndirectsPerBlock2;
|
||||||
else {
|
else {
|
||||||
panic("Undefinied recursion level\n");
|
panic("Undefined recursion level\n");
|
||||||
elementWidth = 0;
|
elementWidth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -868,9 +868,8 @@ Inode::RemovedFromTransaction()
|
|||||||
status_t
|
status_t
|
||||||
Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
|
Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
|
||||||
{
|
{
|
||||||
// TODO: Update fNode.num_blocks
|
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
return B_BAD_DATA;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
TRACE("Inode::_EnlargeDataStream()\n");
|
TRACE("Inode::_EnlargeDataStream()\n");
|
||||||
|
|
||||||
@@ -883,7 +882,7 @@ Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
|
|||||||
if (size <= maxSize) {
|
if (size <= maxSize) {
|
||||||
// No need to allocate more blocks
|
// No need to allocate more blocks
|
||||||
TRACE("Inode::_EnlargeDataStream(): No need to allocate more blocks\n");
|
TRACE("Inode::_EnlargeDataStream(): No need to allocate more blocks\n");
|
||||||
TRACE("Inode::_EnlargeDataStream(): Setting size to %ld\n", (long)size);
|
TRACE("Inode::_EnlargeDataStream(): Setting size to %Ld\n", size);
|
||||||
fNode.SetSize(size);
|
fNode.SetSize(size);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -892,13 +891,11 @@ Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
|
|||||||
DataStream stream(fVolume, &fNode.stream, oldSize);
|
DataStream stream(fVolume, &fNode.stream, oldSize);
|
||||||
stream.Enlarge(transaction, end);
|
stream.Enlarge(transaction, end);
|
||||||
|
|
||||||
TRACE("Inode::_EnlargeDataStream(): Setting size to %ld\n", (long)size);
|
TRACE("Inode::_EnlargeDataStream(): Setting size to %Ld\n", size);
|
||||||
fNode.SetSize(size);
|
fNode.SetSize(size);
|
||||||
TRACE("Inode::_EnlargeDataStream(): Setting allocated block count to %lu\n",
|
TRACE("Inode::_EnlargeDataStream(): Setting allocated block count to %lu\n",
|
||||||
end);
|
end);
|
||||||
fNode.SetNumBlocks(fNode.NumBlocks() + end * (fVolume->BlockSize() / 512));
|
return _SetNumBlocks(_NumBlocks() + end * (fVolume->BlockSize() / 512));
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -908,7 +905,7 @@ Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
|
|||||||
TRACE("Inode::_ShrinkDataStream()\n");
|
TRACE("Inode::_ShrinkDataStream()\n");
|
||||||
|
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
return B_BAD_DATA;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
uint32 blockSize = fVolume->BlockSize();
|
uint32 blockSize = fVolume->BlockSize();
|
||||||
off_t oldSize = Size();
|
off_t oldSize = Size();
|
||||||
@@ -929,7 +926,40 @@ Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
|
|||||||
stream.Shrink(transaction, end);
|
stream.Shrink(transaction, end);
|
||||||
|
|
||||||
fNode.SetSize(size);
|
fNode.SetSize(size);
|
||||||
fNode.SetNumBlocks(fNode.NumBlocks() - end * (fVolume->BlockSize() / 512));
|
return _SetNumBlocks(_NumBlocks() - end * (fVolume->BlockSize() / 512));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint64
|
||||||
|
Inode::_NumBlocks()
|
||||||
|
{
|
||||||
|
if (fVolume->HugeFiles()) {
|
||||||
|
if (fNode.Flags() & EXT2_INODE_HUGE_FILE)
|
||||||
|
return fNode.NumBlocks64() * (fVolume->BlockSize() / 512);
|
||||||
|
else
|
||||||
|
return fNode.NumBlocks64();
|
||||||
|
} else
|
||||||
|
return fNode.NumBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::_SetNumBlocks(uint64 numBlocks)
|
||||||
|
{
|
||||||
|
if (numBlocks <= 0xffffffff) {
|
||||||
|
fNode.SetNumBlocks(numBlocks);
|
||||||
|
fNode.ClearFlag(EXT2_INODE_HUGE_FILE);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
if (!fVolume->HugeFiles())
|
||||||
|
return E2BIG;
|
||||||
|
|
||||||
|
if (numBlocks > 0xffffffffffffULL) {
|
||||||
|
fNode.SetFlag(EXT2_INODE_HUGE_FILE);
|
||||||
|
numBlocks /= (fVolume->BlockSize() / 512);
|
||||||
|
} else
|
||||||
|
fNode.ClearFlag(EXT2_INODE_HUGE_FILE);
|
||||||
|
|
||||||
|
fNode.SetNumBlocks64(numBlocks);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ private:
|
|||||||
off_t size);
|
off_t size);
|
||||||
status_t _ShrinkDataStream(Transaction& transaction, off_t size);
|
status_t _ShrinkDataStream(Transaction& transaction, off_t size);
|
||||||
|
|
||||||
|
uint64 _NumBlocks();
|
||||||
|
status_t _SetNumBlocks(uint64 numBlocks);
|
||||||
|
|
||||||
rw_lock fLock;
|
rw_lock fLock;
|
||||||
::Volume* fVolume;
|
::Volume* fVolume;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#else
|
#else
|
||||||
# define TRACE(x...) ;
|
# define TRACE(x...) ;
|
||||||
#endif
|
#endif
|
||||||
|
# define FATAL(x...) dprintf("\33[34mext2:\33[0m " x)
|
||||||
|
|
||||||
|
|
||||||
class DeviceOpener {
|
class DeviceOpener {
|
||||||
@@ -284,13 +285,17 @@ Volume::Mount(const char* deviceName, uint32 flags)
|
|||||||
if (opener.IsReadOnly())
|
if (opener.IsReadOnly())
|
||||||
fFlags |= VOLUME_READ_ONLY;
|
fFlags |= VOLUME_READ_ONLY;
|
||||||
|
|
||||||
// read the super block
|
TRACE("features %lx, incompatible features %lx, read-only features %lx\n",
|
||||||
if (Identify(fDevice, &fSuperBlock) != B_OK) {
|
fSuperBlock.CompatibleFeatures(), fSuperBlock.IncompatibleFeatures(),
|
||||||
//FATAL(("invalid super block!\n"));
|
fSuperBlock.ReadOnlyFeatures());
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_UnsupportedIncompatibleFeatures(fSuperBlock) != 0)
|
// read the super block
|
||||||
|
status_t status = Identify(fDevice, &fSuperBlock);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// check read-only features if mounting read-write
|
||||||
|
if (!IsReadOnly() && _UnsupportedReadOnlyFeatures(fSuperBlock) != 0)
|
||||||
return B_NOT_SUPPORTED;
|
return B_NOT_SUPPORTED;
|
||||||
|
|
||||||
// initialize short hands to the super block (to save byte swapping)
|
// initialize short hands to the super block (to save byte swapping)
|
||||||
@@ -312,10 +317,7 @@ Volume::Mount(const char* deviceName, uint32 flags)
|
|||||||
|
|
||||||
TRACE("block size %ld, num groups %ld, groups per block %ld, first %lu\n",
|
TRACE("block size %ld, num groups %ld, groups per block %ld, first %lu\n",
|
||||||
fBlockSize, fNumGroups, fGroupsPerBlock, fFirstDataBlock);
|
fBlockSize, fNumGroups, fGroupsPerBlock, fFirstDataBlock);
|
||||||
TRACE("features %lx, incompatible features %lx, read-only features %lx\n",
|
|
||||||
fSuperBlock.CompatibleFeatures(), fSuperBlock.IncompatibleFeatures(),
|
|
||||||
fSuperBlock.ReadOnlyFeatures());
|
|
||||||
|
|
||||||
uint32 blockCount = (fNumGroups + fGroupsPerBlock - 1) / fGroupsPerBlock;
|
uint32 blockCount = (fNumGroups + fGroupsPerBlock - 1) / fGroupsPerBlock;
|
||||||
|
|
||||||
fGroupBlocks = (ext2_block_group**)malloc(blockCount * sizeof(void*));
|
fGroupBlocks = (ext2_block_group**)malloc(blockCount * sizeof(void*));
|
||||||
@@ -327,7 +329,7 @@ Volume::Mount(const char* deviceName, uint32 flags)
|
|||||||
|
|
||||||
// check if the device size is large enough to hold the file system
|
// check if the device size is large enough to hold the file system
|
||||||
off_t diskSize;
|
off_t diskSize;
|
||||||
status_t status = opener.GetSize(&diskSize);
|
status = opener.GetSize(&diskSize);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
if (diskSize < (NumBlocks() << BlockShift()))
|
if (diskSize < (NumBlocks() << BlockShift()))
|
||||||
@@ -339,8 +341,9 @@ Volume::Mount(const char* deviceName, uint32 flags)
|
|||||||
|
|
||||||
TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache);
|
TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache);
|
||||||
|
|
||||||
// initialize journal
|
// initialize journal if mounted read-write
|
||||||
if ((fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
|
if (!IsReadOnly() &&
|
||||||
|
(fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
|
||||||
// TODO: There should be a mount option to ignore the existent journal
|
// TODO: There should be a mount option to ignore the existent journal
|
||||||
if (fSuperBlock.JournalInode() != 0) {
|
if (fSuperBlock.JournalInode() != 0) {
|
||||||
fJournalInode = new(std::nothrow) Inode(this,
|
fJournalInode = new(std::nothrow) Inode(this,
|
||||||
@@ -469,15 +472,32 @@ Volume::_UnsupportedIncompatibleFeatures(ext2_super_block& superBlock)
|
|||||||
| EXT2_INCOMPATIBLE_FEATURE_RECOVER
|
| EXT2_INCOMPATIBLE_FEATURE_RECOVER
|
||||||
| EXT2_INCOMPATIBLE_FEATURE_JOURNAL
|
| EXT2_INCOMPATIBLE_FEATURE_JOURNAL
|
||||||
/*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/;
|
/*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/;
|
||||||
|
uint32 unsupported = superBlock.IncompatibleFeatures()
|
||||||
|
& ~supportedIncompatible;
|
||||||
|
|
||||||
if ((superBlock.IncompatibleFeatures() & ~supportedIncompatible) != 0) {
|
if (unsupported != 0) {
|
||||||
dprintf("ext2: incompatible features not supported: %lx (extents %x)\n",
|
FATAL("ext2: incompatible features not supported: %lx (extents %x)\n",
|
||||||
superBlock.IncompatibleFeatures() & ~supportedIncompatible,
|
unsupported, EXT2_INCOMPATIBLE_FEATURE_EXTENTS);
|
||||||
EXT2_INCOMPATIBLE_FEATURE_EXTENTS);
|
|
||||||
return superBlock.IncompatibleFeatures() & ~supportedIncompatible;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return unsupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ uint32
|
||||||
|
Volume::_UnsupportedReadOnlyFeatures(ext2_super_block& superBlock)
|
||||||
|
{
|
||||||
|
uint32 supportedReadOnly = EXT2_READ_ONLY_FEATURE_SPARSE_SUPER
|
||||||
|
| EXT2_READ_ONLY_FEATURE_HUGE_FILE;
|
||||||
|
// TODO actually implement EXT2_READ_ONLY_FEATURE_SPARSE_SUPER when
|
||||||
|
// implementing superblock backup copies
|
||||||
|
|
||||||
|
uint32 unsupported = superBlock.ReadOnlyFeatures() & ~supportedReadOnly;
|
||||||
|
|
||||||
|
if (unsupported != 0)
|
||||||
|
FATAL("ext2: readonly features not supported: %lx\n", unsupported);
|
||||||
|
|
||||||
|
return unsupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -796,8 +816,10 @@ Volume::Identify(int fd, ext2_super_block* superBlock)
|
|||||||
sizeof(ext2_super_block)) != sizeof(ext2_super_block))
|
sizeof(ext2_super_block)) != sizeof(ext2_super_block))
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
if (!superBlock->IsValid())
|
if (!superBlock->IsValid()) {
|
||||||
|
FATAL("invalid super block!\n");
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
return _UnsupportedIncompatibleFeatures(*superBlock) == 0
|
return _UnsupportedIncompatibleFeatures(*superBlock) == 0
|
||||||
? B_OK : B_NOT_SUPPORTED;
|
? B_OK : B_NOT_SUPPORTED;
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ public:
|
|||||||
& EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
|
& EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
|
||||||
uint8 DefaultHashVersion() const
|
uint8 DefaultHashVersion() const
|
||||||
{ return fSuperBlock.default_hash_version; }
|
{ return fSuperBlock.default_hash_version; }
|
||||||
|
bool HugeFiles() const
|
||||||
|
{ return (fSuperBlock.ReadOnlyFeatures()
|
||||||
|
& EXT2_READ_ONLY_FEATURE_HUGE_FILE) != 0; }
|
||||||
|
|
||||||
status_t SaveOrphan(Transaction& transaction,
|
status_t SaveOrphan(Transaction& transaction,
|
||||||
ino_t newID, ino_t &oldID);
|
ino_t newID, ino_t &oldID);
|
||||||
@@ -115,6 +118,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
static uint32 _UnsupportedIncompatibleFeatures(
|
static uint32 _UnsupportedIncompatibleFeatures(
|
||||||
ext2_super_block& superBlock);
|
ext2_super_block& superBlock);
|
||||||
|
static uint32 _UnsupportedReadOnlyFeatures(
|
||||||
|
ext2_super_block& superBlock);
|
||||||
uint32 _GroupDescriptorBlock(uint32 blockIndex);
|
uint32 _GroupDescriptorBlock(uint32 blockIndex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ struct ext2_super_block {
|
|||||||
#define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER 0x0001
|
#define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER 0x0001
|
||||||
#define EXT2_READ_ONLY_FEATURE_LARGE_FILE 0x0002
|
#define EXT2_READ_ONLY_FEATURE_LARGE_FILE 0x0002
|
||||||
#define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY 0x0004
|
#define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY 0x0004
|
||||||
|
#define EXT2_READ_ONLY_FEATURE_HUGE_FILE 0x0008
|
||||||
|
|
||||||
// incompatible features
|
// incompatible features
|
||||||
#define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION 0x0001
|
#define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION 0x0001
|
||||||
@@ -234,8 +235,13 @@ struct ext2_inode {
|
|||||||
uint32 size_high;
|
uint32 size_high;
|
||||||
};
|
};
|
||||||
uint32 fragment;
|
uint32 fragment;
|
||||||
uint8 fragment_number;
|
union {
|
||||||
uint8 fragment_size;
|
struct {
|
||||||
|
uint8 fragment_number;
|
||||||
|
uint8 fragment_size;
|
||||||
|
};
|
||||||
|
uint16 num_blocks_high;
|
||||||
|
};
|
||||||
uint16 _padding;
|
uint16 _padding;
|
||||||
uint16 uid_high;
|
uint16 uid_high;
|
||||||
uint16 gid_high;
|
uint16 gid_high;
|
||||||
@@ -247,6 +253,8 @@ struct ext2_inode {
|
|||||||
uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
|
uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
|
||||||
uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
|
uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
|
||||||
uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
|
uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
|
||||||
|
uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
|
||||||
|
| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
|
||||||
|
|
||||||
time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
|
time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
|
||||||
time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
|
time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
|
||||||
@@ -286,6 +294,11 @@ struct ext2_inode {
|
|||||||
SetMode((Mode() & ~mask) | (newMode & mask));
|
SetMode((Mode() & ~mask) | (newMode & mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearFlag(uint32 mask)
|
||||||
|
{
|
||||||
|
flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
|
||||||
|
}
|
||||||
|
|
||||||
void SetFlag(uint32 mask)
|
void SetFlag(uint32 mask)
|
||||||
{
|
{
|
||||||
flags |= B_HOST_TO_LENDIAN_INT32(mask);
|
flags |= B_HOST_TO_LENDIAN_INT32(mask);
|
||||||
@@ -306,6 +319,12 @@ struct ext2_inode {
|
|||||||
num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
|
num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetNumBlocks64(uint64 numBlocks)
|
||||||
|
{
|
||||||
|
num_blocks = B_HOST_TO_LENDIAN_INT32(numBlocks & 0xffffffff);
|
||||||
|
num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
void SetAccessTime(time_t accessTime)
|
void SetAccessTime(time_t accessTime)
|
||||||
{
|
{
|
||||||
access_time = B_HOST_TO_LENDIAN_INT32((uint32)accessTime);
|
access_time = B_HOST_TO_LENDIAN_INT32((uint32)accessTime);
|
||||||
@@ -373,6 +392,7 @@ struct ext2_inode {
|
|||||||
#define EXT2_INODE_COMPRESSION_ERROR 0x00000800
|
#define EXT2_INODE_COMPRESSION_ERROR 0x00000800
|
||||||
#define EXT2_INODE_BTREE 0x00001000
|
#define EXT2_INODE_BTREE 0x00001000
|
||||||
#define EXT2_INODE_INDEXED 0x00001000
|
#define EXT2_INODE_INDEXED 0x00001000
|
||||||
|
#define EXT2_INODE_HUGE_FILE 0x00040000
|
||||||
|
|
||||||
#define EXT2_NAME_LENGTH 255
|
#define EXT2_NAME_LENGTH 255
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user