* 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;
|
||||
|
||||
index += 1;
|
||||
}
|
||||
} else
|
||||
iterations++;
|
||||
|
||||
for (; iterations > 0; --iterations) {
|
||||
if (data[index++] != 0)
|
||||
@@ -153,7 +154,8 @@ BitmapBlock::CheckMarked(uint32 start, uint32 length)
|
||||
return false;
|
||||
|
||||
index += 1;
|
||||
}
|
||||
} else
|
||||
iterations++;
|
||||
|
||||
mask = 0xFFFFFFFF;
|
||||
for (; iterations > 0; --iterations) {
|
||||
@@ -216,7 +218,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
|
||||
mask = ~((1 << startBit) - 1);
|
||||
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)
|
||||
return false;
|
||||
@@ -225,7 +228,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
|
||||
fData[index] = B_HOST_TO_LENDIAN_INT32(bits);
|
||||
|
||||
index += 1;
|
||||
}
|
||||
} else
|
||||
iterations++;
|
||||
|
||||
mask = 0xFFFFFFFF;
|
||||
for (; iterations > 0; --iterations) {
|
||||
@@ -237,8 +241,8 @@ BitmapBlock::Mark(uint32 start, uint32 length, bool force)
|
||||
if (remainingBits != 0) {
|
||||
mask = (1 << remainingBits) - 1;
|
||||
uint32 bits = B_LENDIAN_TO_HOST_INT32(fData[index]);
|
||||
TRACE("BitmapBlock::(): marking remaining %lu bits: %lX, mask: %lX\n",
|
||||
remainingBits, bits, mask);
|
||||
TRACE("BitmapBlock::Mark(): marking index %lu remaining %lu bits: %lX,"
|
||||
" mask: %lX\n", index, remainingBits, bits, mask);
|
||||
|
||||
if (!force && (bits & mask) != 0)
|
||||
return false;
|
||||
@@ -310,7 +314,8 @@ BitmapBlock::Unmark(uint32 start, uint32 length, bool force)
|
||||
|
||||
TRACE("BitmapBlock::Unmark(): updated bits: %lx\n", bits);
|
||||
index += 1;
|
||||
}
|
||||
} else
|
||||
iterations++;
|
||||
|
||||
mask = 0xFFFFFFFF;
|
||||
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,
|
||||
uint32& length);
|
||||
|
||||
uint32 NumBits() const;
|
||||
uint32 NumBits() const { return fNumBits; }
|
||||
|
||||
protected:
|
||||
uint32* fData;
|
||||
|
||||
@@ -180,7 +180,7 @@ status_t
|
||||
AllocationBlockGroup::Allocate(Transaction& transaction, uint32 start,
|
||||
uint32 length)
|
||||
{
|
||||
TRACE("AllocationBlockGroup::Allocate()\n");
|
||||
TRACE("AllocationBlockGroup::Allocate(%ld,%ld)\n", start, length);
|
||||
uint32 end = start + length;
|
||||
if (end > fNumBits)
|
||||
return B_BAD_DATA;
|
||||
@@ -463,7 +463,7 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, uint32 minimum,
|
||||
{
|
||||
TRACE("BlockAllocator::AllocateBlocks()\n");
|
||||
MutexLocker lock(fLock);
|
||||
TRACE("BlockAllocator::AllocateBlocks(): Aquired lock\n");
|
||||
TRACE("BlockAllocator::AllocateBlocks(): Acquired lock\n");
|
||||
|
||||
TRACE("BlockAllocator::AllocateBlocks(): transaction: %ld, min: %lu, "
|
||||
"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)
|
||||
:
|
||||
kBlockSize(volume->BlockSize()),
|
||||
kIndirectsPerBlock(kBlockSize / 4),
|
||||
kIndirectsPerBlock(kBlockSize / sizeof(uint32)),
|
||||
kIndirectsPerBlock2(kIndirectsPerBlock * kIndirectsPerBlock),
|
||||
kIndirectsPerBlock3(kIndirectsPerBlock2 * kIndirectsPerBlock),
|
||||
kMaxDirect(EXT2_DIRECT_BLOCKS),
|
||||
@@ -195,20 +195,9 @@ DataStream::_BlocksNeeded(uint32 numBlocks)
|
||||
blocksNeeded += 2 + (numBlocks - kMaxIndirect - 1)
|
||||
/ kIndirectsPerBlock;
|
||||
} else {
|
||||
blocksNeeded += (numBlocks - fNumBlocks)
|
||||
/ 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++;
|
||||
blocksNeeded += (numBlocks - kMaxIndirect - 1)
|
||||
/ kIndirectsPerBlock - (fNumBlocks
|
||||
- kMaxIndirect - 1) / kIndirectsPerBlock;
|
||||
}
|
||||
|
||||
if (numBlocks > kMaxDoubleIndirect) {
|
||||
@@ -216,21 +205,9 @@ DataStream::_BlocksNeeded(uint32 numBlocks)
|
||||
blocksNeeded += 2 + (numBlocks - kMaxDoubleIndirect - 1)
|
||||
/ kIndirectsPerBlock2;
|
||||
} else {
|
||||
blocksNeeded += (numBlocks - fNumBlocks)
|
||||
/ kIndirectsPerBlock2;
|
||||
|
||||
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++;
|
||||
blocksNeeded += (numBlocks - kMaxDoubleIndirect - 1)
|
||||
/ kIndirectsPerBlock - (fNumBlocks
|
||||
- kMaxDoubleIndirect - 1) / kIndirectsPerBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,6 +237,9 @@ DataStream::_GetBlock(Transaction& transaction, uint32& block)
|
||||
|
||||
fWaiting -= fAllocated;
|
||||
fAllocatedPos += fVolume->BlocksPerGroup() * blockGroup + fFirstBlock;
|
||||
|
||||
TRACE("DataStream::_GetBlock(): newAllocated: %lu, newpos: %lu,"
|
||||
"newwaiting: %lu\n", fAllocated, fAllocatedPos, fWaiting);
|
||||
}
|
||||
|
||||
fAllocated--;
|
||||
@@ -339,7 +319,7 @@ DataStream::_AddBlocks(Transaction& transaction, uint32* block, uint32 start,
|
||||
else if (recursion == 2)
|
||||
elementWidth = kIndirectsPerBlock2;
|
||||
else {
|
||||
panic("Undefinied recursion level\n");
|
||||
panic("Undefined recursion level\n");
|
||||
elementWidth = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -868,9 +868,8 @@ Inode::RemovedFromTransaction()
|
||||
status_t
|
||||
Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
|
||||
{
|
||||
// TODO: Update fNode.num_blocks
|
||||
if (size < 0)
|
||||
return B_BAD_DATA;
|
||||
return B_BAD_VALUE;
|
||||
|
||||
TRACE("Inode::_EnlargeDataStream()\n");
|
||||
|
||||
@@ -883,7 +882,7 @@ Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
|
||||
if (size <= maxSize) {
|
||||
// No need to allocate more blocks
|
||||
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);
|
||||
return B_OK;
|
||||
}
|
||||
@@ -892,13 +891,11 @@ Inode::_EnlargeDataStream(Transaction& transaction, off_t size)
|
||||
DataStream stream(fVolume, &fNode.stream, oldSize);
|
||||
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);
|
||||
TRACE("Inode::_EnlargeDataStream(): Setting allocated block count to %lu\n",
|
||||
end);
|
||||
fNode.SetNumBlocks(fNode.NumBlocks() + end * (fVolume->BlockSize() / 512));
|
||||
|
||||
return B_OK;
|
||||
return _SetNumBlocks(_NumBlocks() + end * (fVolume->BlockSize() / 512));
|
||||
}
|
||||
|
||||
|
||||
@@ -908,7 +905,7 @@ Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
|
||||
TRACE("Inode::_ShrinkDataStream()\n");
|
||||
|
||||
if (size < 0)
|
||||
return B_BAD_DATA;
|
||||
return B_BAD_VALUE;
|
||||
|
||||
uint32 blockSize = fVolume->BlockSize();
|
||||
off_t oldSize = Size();
|
||||
@@ -929,7 +926,40 @@ Inode::_ShrinkDataStream(Transaction& transaction, off_t size)
|
||||
stream.Shrink(transaction, end);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -100,6 +100,8 @@ private:
|
||||
off_t size);
|
||||
status_t _ShrinkDataStream(Transaction& transaction, off_t size);
|
||||
|
||||
uint64 _NumBlocks();
|
||||
status_t _SetNumBlocks(uint64 numBlocks);
|
||||
|
||||
rw_lock fLock;
|
||||
::Volume* fVolume;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
# define FATAL(x...) dprintf("\33[34mext2:\33[0m " x)
|
||||
|
||||
|
||||
class DeviceOpener {
|
||||
@@ -284,13 +285,17 @@ Volume::Mount(const char* deviceName, uint32 flags)
|
||||
if (opener.IsReadOnly())
|
||||
fFlags |= VOLUME_READ_ONLY;
|
||||
|
||||
// read the super block
|
||||
if (Identify(fDevice, &fSuperBlock) != B_OK) {
|
||||
//FATAL(("invalid super block!\n"));
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
TRACE("features %lx, incompatible features %lx, read-only features %lx\n",
|
||||
fSuperBlock.CompatibleFeatures(), fSuperBlock.IncompatibleFeatures(),
|
||||
fSuperBlock.ReadOnlyFeatures());
|
||||
|
||||
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;
|
||||
|
||||
// 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",
|
||||
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;
|
||||
|
||||
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
|
||||
off_t diskSize;
|
||||
status_t status = opener.GetSize(&diskSize);
|
||||
status = opener.GetSize(&diskSize);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
if (diskSize < (NumBlocks() << BlockShift()))
|
||||
@@ -339,8 +341,9 @@ Volume::Mount(const char* deviceName, uint32 flags)
|
||||
|
||||
TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache);
|
||||
|
||||
// initialize journal
|
||||
if ((fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
|
||||
// initialize journal if mounted read-write
|
||||
if (!IsReadOnly() &&
|
||||
(fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) {
|
||||
// TODO: There should be a mount option to ignore the existent journal
|
||||
if (fSuperBlock.JournalInode() != 0) {
|
||||
fJournalInode = new(std::nothrow) Inode(this,
|
||||
@@ -469,15 +472,32 @@ Volume::_UnsupportedIncompatibleFeatures(ext2_super_block& superBlock)
|
||||
| EXT2_INCOMPATIBLE_FEATURE_RECOVER
|
||||
| EXT2_INCOMPATIBLE_FEATURE_JOURNAL
|
||||
/*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/;
|
||||
uint32 unsupported = superBlock.IncompatibleFeatures()
|
||||
& ~supportedIncompatible;
|
||||
|
||||
if ((superBlock.IncompatibleFeatures() & ~supportedIncompatible) != 0) {
|
||||
dprintf("ext2: incompatible features not supported: %lx (extents %x)\n",
|
||||
superBlock.IncompatibleFeatures() & ~supportedIncompatible,
|
||||
EXT2_INCOMPATIBLE_FEATURE_EXTENTS);
|
||||
return superBlock.IncompatibleFeatures() & ~supportedIncompatible;
|
||||
if (unsupported != 0) {
|
||||
FATAL("ext2: incompatible features not supported: %lx (extents %x)\n",
|
||||
unsupported, EXT2_INCOMPATIBLE_FEATURE_EXTENTS);
|
||||
}
|
||||
|
||||
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))
|
||||
return B_IO_ERROR;
|
||||
|
||||
if (!superBlock->IsValid())
|
||||
if (!superBlock->IsValid()) {
|
||||
FATAL("invalid super block!\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
return _UnsupportedIncompatibleFeatures(*superBlock) == 0
|
||||
? B_OK : B_NOT_SUPPORTED;
|
||||
|
||||
@@ -79,6 +79,9 @@ public:
|
||||
& EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
|
||||
uint8 DefaultHashVersion() const
|
||||
{ return fSuperBlock.default_hash_version; }
|
||||
bool HugeFiles() const
|
||||
{ return (fSuperBlock.ReadOnlyFeatures()
|
||||
& EXT2_READ_ONLY_FEATURE_HUGE_FILE) != 0; }
|
||||
|
||||
status_t SaveOrphan(Transaction& transaction,
|
||||
ino_t newID, ino_t &oldID);
|
||||
@@ -115,6 +118,8 @@ public:
|
||||
private:
|
||||
static uint32 _UnsupportedIncompatibleFeatures(
|
||||
ext2_super_block& superBlock);
|
||||
static uint32 _UnsupportedReadOnlyFeatures(
|
||||
ext2_super_block& superBlock);
|
||||
uint32 _GroupDescriptorBlock(uint32 blockIndex);
|
||||
|
||||
private:
|
||||
|
||||
@@ -149,6 +149,7 @@ struct ext2_super_block {
|
||||
#define EXT2_READ_ONLY_FEATURE_SPARSE_SUPER 0x0001
|
||||
#define EXT2_READ_ONLY_FEATURE_LARGE_FILE 0x0002
|
||||
#define EXT2_READ_ONLY_FEATURE_BTREE_DIRECTORY 0x0004
|
||||
#define EXT2_READ_ONLY_FEATURE_HUGE_FILE 0x0008
|
||||
|
||||
// incompatible features
|
||||
#define EXT2_INCOMPATIBLE_FEATURE_COMPRESSION 0x0001
|
||||
@@ -234,8 +235,13 @@ struct ext2_inode {
|
||||
uint32 size_high;
|
||||
};
|
||||
uint32 fragment;
|
||||
uint8 fragment_number;
|
||||
uint8 fragment_size;
|
||||
union {
|
||||
struct {
|
||||
uint8 fragment_number;
|
||||
uint8 fragment_size;
|
||||
};
|
||||
uint16 num_blocks_high;
|
||||
};
|
||||
uint16 _padding;
|
||||
uint16 uid_high;
|
||||
uint16 gid_high;
|
||||
@@ -247,6 +253,8 @@ struct ext2_inode {
|
||||
uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
|
||||
uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); }
|
||||
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 CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
|
||||
@@ -286,6 +294,11 @@ struct ext2_inode {
|
||||
SetMode((Mode() & ~mask) | (newMode & mask));
|
||||
}
|
||||
|
||||
void ClearFlag(uint32 mask)
|
||||
{
|
||||
flags &= ~B_HOST_TO_LENDIAN_INT32(mask);
|
||||
}
|
||||
|
||||
void SetFlag(uint32 mask)
|
||||
{
|
||||
flags |= B_HOST_TO_LENDIAN_INT32(mask);
|
||||
@@ -306,6 +319,12 @@ struct ext2_inode {
|
||||
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)
|
||||
{
|
||||
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_BTREE 0x00001000
|
||||
#define EXT2_INODE_INDEXED 0x00001000
|
||||
#define EXT2_INODE_HUGE_FILE 0x00040000
|
||||
|
||||
#define EXT2_NAME_LENGTH 255
|
||||
|
||||
|
||||
Reference in New Issue
Block a user