* 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:
Jérôme Duval
2010-10-11 19:58:46 +00:00
parent b0ce12a2af
commit de66992b72
9 changed files with 136 additions and 78 deletions
@@ -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;
} }
+39 -9
View File
@@ -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;
+41 -19
View File
@@ -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,9 +317,6 @@ 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;
@@ -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:
+22 -2
View File
@@ -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