Patch from Janito Ferreira Filho with fixes by myself: Ext3 Indexed Directory Lookup (as part of GSOC).

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37295 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2010-06-28 21:38:37 +00:00
parent 307ff45454
commit 919f9c41da
13 changed files with 938 additions and 10 deletions

View File

@ -8,6 +8,7 @@
#include <string.h>
#include "HTree.h"
#include "Inode.h"
@ -35,8 +36,10 @@ DirectoryIterator::~DirectoryIterator()
status_t
DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
{
if (fOffset + sizeof(ext2_dir_entry) >= fInode->Size())
if (fOffset + sizeof(ext2_dir_entry) >= fInode->Size()) {
TRACE("DirectoryIterator::GetNext() out of entries\n");
return B_ENTRY_NOT_FOUND;
}
ext2_dir_entry entry;
@ -54,6 +57,7 @@ DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
break;
fOffset += entry.Length();
TRACE("DirectoryIterator::GetNext() skipping entry\n");
}
TRACE("offset %Ld: entry ino %lu, length %u, name length %u, type %u\n",

View File

@ -14,18 +14,18 @@ class Inode;
class DirectoryIterator {
public:
DirectoryIterator(Inode* inode);
~DirectoryIterator();
virtual ~DirectoryIterator();
status_t GetNext(char* name, size_t* _nameLength, ino_t* id);
virtual status_t GetNext(char* name, size_t* _nameLength, ino_t* id);
status_t Rewind();
virtual status_t Rewind();
private:
DirectoryIterator(const DirectoryIterator&);
DirectoryIterator &operator=(const DirectoryIterator&);
// no implementation
private:
protected:
Inode* fInode;
off_t fOffset;
};

View File

@ -0,0 +1,376 @@
/*
* Copyright 2010, Haiku Inc. All rights reserved.
* This file may be used under the terms of the MIT License.
*
* Authors:
* Janito V. Ferreira Filho
*/
#include "HTree.h"
#include <new>
#include <string.h>
#include "HTreeEntryIterator.h"
#include "Inode.h"
#include "Volume.h"
//#define TRACE_EXT2
#ifdef TRACE_EXT2
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
#else
# define TRACE(x...) ;
#endif
bool
HTreeRoot::IsValid() const
{
if (reserved != 0)
return false;
if (hash_version != HTREE_HASH_LEGACY
&& hash_version != HTREE_HASH_HALF_MD4
&& hash_version != HTREE_HASH_TEA)
return false;
if (root_info_length != 8)
return false;
if (indirection_levels > 1)
return false;
// TODO: Maybe we should check the false directory entries too?
return true;
}
HTree::HTree(Volume* volume, Inode* directory)
:
fDirectory(directory),
fRootEntry(NULL)
{
fBlockSize = volume->BlockSize();
fIndexed = volume->IndexedDirectories()
&& (directory->Flags() & EXT2_INODE_INDEXED) != 0;
ext2_super_block superBlock = volume->SuperBlock();
fHashSeed[0] = superBlock.HashSeed(0);
fHashSeed[1] = superBlock.HashSeed(1);
fHashSeed[2] = superBlock.HashSeed(2);
fHashSeed[3] = superBlock.HashSeed(3);
TRACE("HTree::HTree() %lx %lx %lx %lx\n", fHashSeed[0],
fHashSeed[1], fHashSeed[2], fHashSeed[3]);
if (fHashSeed[0] == 0 && fHashSeed[1] == 0 && fHashSeed[2] == 0
&& fHashSeed[3] == 0) {
fHashSeed[0] = 0x67452301;
fHashSeed[1] = 0xefcdab89;
fHashSeed[2] = 0x98badcfe;
fHashSeed[3] = 0x10325476;
}
}
HTree::~HTree()
{
}
status_t
HTree::Lookup(const char* name, DirectoryIterator** iterator)
{
if (!fIndexed || (name[0] == '.'
&& (name[1] == '\0' || (name[1] == '.' && name[2] == '0')))) {
// No HTree support or looking for trivial directories
// TODO: Does these directories get hashed?
*iterator = new(std::nothrow) DirectoryIterator(fDirectory);
if (*iterator == NULL)
return B_NO_MEMORY;
return B_OK;
}
HTreeRoot root;
size_t length = sizeof(root);
status_t status = fDirectory->ReadAt(0, (uint8*)&root, &length);
if (status < B_OK)
return status;
if (length != sizeof(root) || !root.IsValid()) {
// Fallback to linear search
*iterator = new(std::nothrow) DirectoryIterator(fDirectory);
if (*iterator == NULL)
return B_NO_MEMORY;
return B_OK;
}
uint32 hash = _Hash(name, root.hash_version);
off_t start = (off_t)root.root_info_length
+ 2 * (sizeof(HTreeFakeDirEntry) + 4);
fRootEntry = new(std::nothrow) HTreeEntryIterator(start, fDirectory);
if (fRootEntry == NULL)
return B_NO_MEMORY;
fRootDeleter.SetTo(fRootEntry);
status = fRootEntry->Init();
if (status != B_OK)
return status;
return fRootEntry->Lookup(hash, (uint32)root.indirection_levels, iterator);
}
uint32
HTree::_Hash(const char* name, uint8 version)
{
uint32 hash;
switch (version) {
case HTREE_HASH_LEGACY:
hash = _HashLegacy(name);
break;
case HTREE_HASH_HALF_MD4:
hash = _HashHalfMD4(name);
break;
case HTREE_HASH_TEA:
hash = _HashTEA(name);
break;
default:
panic("Hash verification succeeded but then failed?");
hash = 0;
};
TRACE("Filename hash: %u\n", hash);
return hash & ~1;
}
uint32
HTree::_HashLegacy(const char* name)
{
uint32 hash = 0x12a3fe2d;
uint32 previous = 0x37abe8f9;
for (; *name != '\0'; ++name) {
uint32 next = previous + (hash ^ (*name * 7152373));
if ((next & 0x80000000) != 0)
next -= 0x7fffffff;
previous = hash;
hash = next;
}
return hash;
}
/*inline*/ uint32
HTree::_MD4F(uint32 x, uint32 y, uint32 z)
{
return z ^ (x & (y ^ z));
}
/*inline*/ uint32
HTree::_MD4G(uint32 x, uint32 y, uint32 z)
{
return (x & y) + ((x ^ y) & z);
}
/*inline*/ uint32
HTree::_MD4H(uint32 x, uint32 y, uint32 z)
{
return x ^ y ^ z;
}
/*inline*/ void
HTree::_MD4RotateVars(uint32& a, uint32& b, uint32& c, uint32& d)
{
uint32 oldD = d;
d = c;
c = b;
b = a;
a = oldD;
}
void
HTree::_HalfMD4Transform(uint32 buffer[4], uint32 blocks[8])
{
uint32 a, b, c, d;
a = buffer[0];
b = buffer[1];
c = buffer[2];
d = buffer[3];
// Round 1
uint32 shifts[4] = { 3, 7, 11, 19 };
for (int i = 0; i < 8; ++i) {
a += _MD4F(b, c, d) + blocks[i];
uint32 shift = shifts[i % 4];
a = (a << shift) | (a >> (32 - shift));
_MD4RotateVars(a, b, c, d);
}
// Round 2
shifts[1] = 5;
shifts[2] = 9;
shifts[3] = 13;
for (int j = 0; j < 2; ++j) {
for (int i = j; i < 4; i += 2) {
a += _MD4G(b, c, d) + blocks[i] + 013240474631UL;
uint32 shift = shifts[i / 2];
a = (a << shift) | (a >> (32 - shift));
_MD4RotateVars(a, b, c, d);
}
}
// Round 3
shifts[1] = 9;
shifts[2] = 11;
shifts[3] = 15;
for (int i = 0; i < 4; ++i) {
a += _MD4H(b, c, d) + blocks[3 - i] + 015666365641UL;
uint32 shift = shifts[i*2];
a = (a << shift) | (a >> (32 - shift));
_MD4RotateVars(a, b, c, d);
a += _MD4H(b, c, d) + blocks[7 - i] + 015666365641UL;
shift = shifts[i*2 + 1];
a = (a << shift) | (a >> (32 - shift));
_MD4RotateVars(a, b, c, d);
}
buffer[0] += a;
buffer[1] += b;
buffer[2] += c;
buffer[3] += d;
}
uint32
HTree::_HashHalfMD4(const char* name)
{
uint32 buffer[4];
buffer[0] = fHashSeed[0];
buffer[1] = fHashSeed[1];
buffer[2] = fHashSeed[2];
buffer[3] = fHashSeed[3];
for (int length = strlen(name); length > 0; length -= 32) {
uint32 blocks[8];
_PrepareBlocksForHash(name, length, blocks, 8);
_HalfMD4Transform(buffer, blocks);
name += 32;
}
return buffer[1];
}
void
HTree::_TEATransform(uint32 buffer[4], uint32 blocks[4])
{
uint32 x, y;
x = buffer[0];
y = buffer[1];
uint32 a, b, c, d;
a = blocks[0];
b = blocks[1];
c = blocks[2];
d = blocks[3];
uint32 sum = 0;
for (int i = 16; i > 0; --i) {
sum += 0x9E3779B9;
x += ((y << 4) + a) ^ (y + sum) ^ ((y >> 5) + b);
y += ((x << 4) + c) ^ (x + sum) ^ ((x >> 5) + d);
}
buffer[0] += x;
buffer[1] += y;
}
uint32
HTree::_HashTEA(const char* name)
{
uint32 buffer[4];
buffer[0] = fHashSeed[0];
buffer[1] = fHashSeed[1];
buffer[2] = fHashSeed[2];
buffer[3] = fHashSeed[3];
for (int length = strlen(name); length > 0; length -= 16) {
uint32 blocks[4];
_PrepareBlocksForHash(name, length, blocks, 4);
TRACE("_HashTEA %lx %lx %lx\n", blocks[0], blocks[1], blocks[2]);
_TEATransform(buffer, blocks);
name += 16;
}
return buffer[0];
}
void
HTree::_PrepareBlocksForHash(const char* string, int length, uint32* blocks,
int numBlocks)
{
uint32 padding = (uint32)length;
padding = (padding << 8) | padding;
padding = (padding << 16) | padding;
int numBytes = numBlocks * 4;
if (length > numBytes)
length = numBytes;
int completeIterations = length / 4;
for (int i = 0; i < completeIterations; ++i) {
uint32 value = 0 | *(string++);
value = (value << 8) | *(string++);
value = (value << 8) | *(string++);
value = (value << 8) | *(string++);
blocks[i] = value;
}
if (completeIterations < numBlocks) {
int remainingBytes = length % 4;
uint32 value = padding;
for (int i = 0; i < remainingBytes; ++i)
value = (value << 8) + *(string++);
blocks[completeIterations] = value;
for (int i = completeIterations + 1; i < numBlocks; ++i)
blocks[i] = padding;
}
}

View File

@ -0,0 +1,134 @@
/*
* Copyright 2010, Haiku Inc. All rights reserved.
* This file may be used under the terms of the MIT License.
*
* Authors:
* Janito V. Ferreira Filho
*/
#ifndef HTREE_H
#define HTREE_H
#include <AutoDeleter.h>
#include "ext2.h"
#include "DirectoryIterator.h"
#include "HTreeEntryIterator.h"
#include "Inode.h"
#define HTREE_HASH_LEGACY 0
#define HTREE_HASH_HALF_MD4 1
#define HTREE_HASH_TEA 2
struct JournalRevokeHeader;
struct HTreeFakeDirEntry {
uint32 inode_num;
uint16 entry_length;
uint8 name_length;
uint8 file_type;
char file_name[0];
uint32 Inode()
{ return B_LENDIAN_TO_HOST_INT32(inode_num); }
} _PACKED;
struct HTreeCountLimit {
uint16 limit;
uint16 count;
uint16 Limit() const
{ return B_LENDIAN_TO_HOST_INT32(limit); }
uint16 Count() const
{ return B_LENDIAN_TO_HOST_INT32(count); }
} _PACKED;
struct HTreeEntry {
uint32 hash;
uint32 block;
uint32 Hash() const
{ return B_LENDIAN_TO_HOST_INT32(hash); }
uint32 Block() const
{ return B_LENDIAN_TO_HOST_INT32(block); }
} _PACKED;
struct HTreeRoot {
HTreeFakeDirEntry dot;
char dot_entry_name[4];
HTreeFakeDirEntry dotdot;
char dotdot_entry_name[4];
uint32 reserved;
uint8 hash_version;
uint8 root_info_length;
uint8 indirection_levels;
uint8 flags;
bool IsValid() const;
// Implemented in HTree.cpp
} _PACKED;
struct HTreeIndirectNode {
HTreeFakeDirEntry fake_entry;
HTreeEntry entries[0];
} _PACKED;
/*! Hash implementations:
* References:
* Main reference: Linux htree patch:
* http://thunk.org/tytso/linux/ext3-dxdir/patch-ext3-dxdir-2.5.40
* Original MD4 hash: (Modified version used)
* http://tools.ietf.org/html/rfc1320
* TEA Wikipedia article: (Modified version used)
* http://en.wikipedia.org/Tiny_Encryption_Algorithm
*/
class HTree {
public:
HTree(Volume* volume, Inode* directory);
~HTree();
status_t Lookup(const char* name,
DirectoryIterator** directory);
private:
status_t _LookupInNode(uint32 hash, off_t& firstEntry,
off_t& lastEntry,
uint32 remainingIndirects);
uint32 _Hash(const char* name, uint8 version);
uint32 _HashLegacy(const char* name);
inline uint32 _MD4F(uint32 x, uint32 y, uint32 z);
inline uint32 _MD4G(uint32 x, uint32 y, uint32 z);
inline uint32 _MD4H(uint32 x, uint32 y, uint32 z);
inline void _MD4RotateVars(uint32& a, uint32& b,
uint32& c, uint32& d);
void _HalfMD4Transform(uint32 buffer[4],
uint32 blocks[8]);
uint32 _HashHalfMD4(const char* name);
void _TEATransform(uint32 buffer[4],
uint32 blocks[4]);
uint32 _HashTEA(const char* name);
void _PrepareBlocksForHash(const char* string,
int length, uint32* blocks, int numBlocks);
bool fIndexed;
uint32 fBlockSize;
Inode* fDirectory;
uint32 fHashSeed[4];
HTreeEntryIterator* fRootEntry;
ObjectDeleter<HTreeEntryIterator> fRootDeleter;
};
#endif // HTREE_H

View File

@ -0,0 +1,220 @@
/*
* Copyright 2010, Haiku Inc. All rights reserved.
* This file may be used under the terms of the MIT License.
*
* Authors:
* Janito V. Ferreira Filho
*/
#include "HTreeEntryIterator.h"
#include <new>
#include "HTree.h"
#include "IndexedDirectoryIterator.h"
#include "Inode.h"
//#define TRACE_EXT2
#ifdef TRACE_EXT2
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
#else
# define TRACE(x...) ;
#endif
#define ERROR(x...) dprintf("\33[34mext2:\33[0m " x)
HTreeEntryIterator::HTreeEntryIterator(off_t offset, Inode* directory)
:
fHasCollision(false),
fDirectory(directory),
fOffset(offset),
fParent(NULL),
fChild(NULL)
{
fBlockSize = fDirectory->GetVolume()->BlockSize();
}
HTreeEntryIterator::HTreeEntryIterator(uint32 block, uint32 blockSize,
Inode* directory, HTreeEntryIterator* parent, bool hasCollision)
:
fHasCollision(hasCollision),
fBlockSize(blockSize),
fDirectory(directory),
fOffset(block * blockSize + sizeof(HTreeFakeDirEntry)),
fParent(parent),
fChild(NULL)
{
TRACE("HTreeEntryIterator::HTreeEntryIterator() block %ld offset %Lx\n",
block, fOffset);
}
status_t
HTreeEntryIterator::Init()
{
size_t length = sizeof(HTreeCountLimit);
HTreeCountLimit countLimit;
status_t status = fDirectory->ReadAt(fOffset, (uint8*)&countLimit,
&length);
if (status != B_OK)
return status;
if (length != sizeof(HTreeCountLimit)) {
ERROR("HTreeEntryIterator::Init() bad length %ld fOffset 0x%Lx\n",
length, fOffset);
fCount = fLimit = 0;
return B_ERROR;
}
fCount = countLimit.Count();
fLimit = countLimit.Limit();
if (fCount >= fLimit) {
ERROR("HTreeEntryIterator::Init() bad fCount %d fOffset 0x%Lx\n",
fCount, fOffset);
fCount = fLimit = 0;
return B_ERROR;
}
if (fParent != NULL &&
fLimit != ((fBlockSize - sizeof(HTreeFakeDirEntry))
/ sizeof(HTreeEntry)) ) {
ERROR("HTreeEntryIterator::Init() bad fLimit %d should be %ld "
"fOffset 0x%Lx\n", fLimit, (fBlockSize - sizeof(HTreeFakeDirEntry))
/ sizeof(HTreeEntry), fOffset);
fCount = fLimit = 0;
return B_ERROR;
}
TRACE("HTreeEntryIterator::Init() count 0x%x limit 0x%x\n", fCount,
fLimit);
fMaxOffset = fOffset + (fCount - 1) * sizeof(HTreeEntry);
return B_OK;
}
HTreeEntryIterator::~HTreeEntryIterator()
{
}
status_t
HTreeEntryIterator::Lookup(uint32 hash, int indirections,
DirectoryIterator** directoryIterator)
{
off_t start = fOffset + sizeof(HTreeEntry);
off_t end = fMaxOffset;
off_t middle = start;
size_t entrySize = sizeof(HTreeEntry);
HTreeEntry entry;
while (start <= end) {
middle = (end - start) / 2;
middle -= middle % entrySize; // Alignment
middle += start;
TRACE("HTreeEntryIterator::Lookup() %d 0x%Lx 0x%Lx 0x%Lx\n",
indirections, start, end, middle);
status_t status = fDirectory->ReadAt(middle, (uint8*)&entry,
&entrySize);
TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, entry.Hash());
if (status != B_OK)
return status;
else if (entrySize != sizeof(entry)) {
// Fallback to linear search
*directoryIterator = new(std::nothrow)
DirectoryIterator(fDirectory);
if (*directoryIterator == NULL)
return B_NO_MEMORY;
return B_OK;
}
if (hash >= entry.Hash())
start = middle + entrySize;
else
end = middle - entrySize;
}
status_t status = fDirectory->ReadAt(start - entrySize, (uint8*)&entry,
&entrySize);
if (status != B_OK)
return status;
if (indirections == 0) {
*directoryIterator = new(std::nothrow)
IndexedDirectoryIterator(entry.Block() * fBlockSize, fBlockSize,
fDirectory, this);
if (*directoryIterator == NULL)
return B_NO_MEMORY;
return B_OK;
}
delete fChild;
fChild = new(std::nothrow) HTreeEntryIterator(entry.Block(), fBlockSize,
fDirectory, this, entry.Hash() & 1 == 1);
if (fChild == NULL)
return B_NO_MEMORY;
fChildDeleter.SetTo(fChild);
status = fChild->Init();
if (status != B_OK)
return status;
return fChild->Lookup(hash, indirections - 1, directoryIterator);
}
status_t
HTreeEntryIterator::GetNext(off_t& childOffset)
{
size_t entrySize = sizeof(HTreeEntry);
fOffset += entrySize;
bool firstEntry = fOffset >= fMaxOffset;
if (firstEntry) {
if (fParent == NULL)
return B_ENTRY_NOT_FOUND;
status_t status = fParent->GetNext(fOffset);
if (status != B_OK)
return status;
status = Init();
if (status != B_OK)
return status;
fHasCollision = fParent->HasCollision();
}
HTreeEntry entry;
status_t status = fDirectory->ReadAt(fOffset, (uint8*)&entry, &entrySize);
if (status != B_OK)
return status;
else if (entrySize != sizeof(entry)) {
// Weird error, try to skip it
return GetNext(childOffset);
}
if (!firstEntry)
fHasCollision = (entry.Hash() & 1) == 1;
childOffset = entry.Block() * fBlockSize;
return B_OK;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2010, Haiku Inc. All rights reserved.
* This file may be used under the terms of the MIT License.
*
* Authors:
* Janito V. Ferreira Filho
*/
#ifndef HTREE_ENTRY_ITERATOR_H
#define HTREE_ENTRY_ITERATOR_H
#include <AutoDeleter.h>
#include "DirectoryIterator.h"
class HTreeEntryIterator {
public:
HTreeEntryIterator(off_t offset,
Inode* directory);
~HTreeEntryIterator();
status_t Init();
status_t Lookup(uint32 hash, int indirections,
DirectoryIterator** iterator);
bool HasCollision() { return fHasCollision; }
status_t GetNext(off_t& offset);
private:
HTreeEntryIterator(uint32 block,
uint32 blockSize, Inode* directory,
HTreeEntryIterator* parent,
bool hasCollision);
private:
bool fHasCollision;
uint16 fLimit, fCount;
uint32 fBlockSize;
Inode* fDirectory;
off_t fOffset;
off_t fMaxOffset;
HTreeEntryIterator* fParent;
HTreeEntryIterator* fChild;
ObjectDeleter<HTreeEntryIterator> fChildDeleter;
};
#endif // HTREE_ENTRY_ITERATOR_H

View File

@ -0,0 +1,75 @@
/*
* Copyright 2010, Haiku Inc. All rights reserved.
* This file may be used under the terms of the MIT License.
*
* Authors:
* Janito V. Ferreira Filho
*/
#include "IndexedDirectoryIterator.h"
#include "ext2.h"
#include "HTree.h"
#include "HTreeEntryIterator.h"
#include "Inode.h"
//#define TRACE_EXT2
#ifdef TRACE_EXT2
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
#else
# define TRACE(x...) ;
#endif
IndexedDirectoryIterator::IndexedDirectoryIterator(off_t start,
uint32 blockSize, Inode* directory, HTreeEntryIterator* parent)
:
DirectoryIterator(directory),
fIndexing(true),
fParent(parent),
fMaxOffset(start + blockSize),
fBlockSize(blockSize),
fMaxAttempts(0)
{
fOffset = start;
}
IndexedDirectoryIterator::~IndexedDirectoryIterator()
{
}
status_t
IndexedDirectoryIterator::GetNext(char* name, size_t* nameLength, ino_t* id)
{
if (fIndexing && fOffset + sizeof(HTreeFakeDirEntry) >= fMaxOffset) {
TRACE("IndexedDirectoryIterator::GetNext() calling next block\n");
status_t status = fParent->GetNext(fOffset);
if (status != B_OK)
return status;
if (fMaxAttempts++ > 4)
return B_ERROR;
fMaxOffset = fOffset + fBlockSize;
}
return DirectoryIterator::GetNext(name, nameLength, id);
}
status_t
IndexedDirectoryIterator::Rewind()
{
// The only way to rewind it is too loose indexing
fOffset = 0;
fMaxOffset = fInode->Size();
fIndexing = false;
return B_OK;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2010, Haiku Inc. All rights reserved.
* This file may be used under the terms of the MIT License.
*
* Authors:
* Janito V. Ferreira Filho
*/
#ifndef INDEXED_DIRECTORY_ITERATOR_H
#define INDEXED_DIRECTORY_ITERATOR_H
#include "DirectoryIterator.h"
class HTreeEntryIterator;
class IndexedDirectoryIterator : public DirectoryIterator {
public:
IndexedDirectoryIterator(off_t start,
uint32 blockSize, Inode* directory,
HTreeEntryIterator* parent);
virtual ~IndexedDirectoryIterator();
status_t GetNext(char* name, size_t* nameLength,
ino_t* id);
status_t Rewind();
private:
bool fIndexing;
HTreeEntryIterator* fParent;
off_t fMaxOffset;
uint32 fBlockSize;
uint32 fMaxAttempts;
};
#endif // INDEXED_DIRECTORY_ITERATOR_H

View File

@ -202,10 +202,13 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
size_t length = *_length;
// set/check boundaries for pos/length
if (pos < 0)
if (pos < 0) {
TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos, length);
return B_BAD_VALUE;
}
if (pos >= Size() || length == 0) {
TRACE("inode %Ld: ReadAt 0 (pos %Ld, length %lu)\n", ID(), pos, length);
*_length = 0;
return B_NO_ERROR;
}

View File

@ -15,6 +15,9 @@ KernelAddon ext2 :
Inode.cpp
AttributeIterator.cpp
DirectoryIterator.cpp
IndexedDirectoryIterator.cpp
HTree.cpp
HTreeEntryIterator.cpp
kernel_interface.cpp
;

View File

@ -55,6 +55,10 @@ public:
uint32 InodeBlockIndex(ino_t id) const;
status_t GetBlockGroup(int32 index,
ext2_block_group** _group);
bool IndexedDirectories() const
{ return (fSuperBlock.CompatibleFeatures()
& EXT2_FEATURE_DIRECTORY_INDEX) != 0; }
// cache access
void* BlockCache() { return fBlockCache; }

View File

@ -86,6 +86,8 @@ struct ext2_super_block {
uint32 _reserved5[162];
uint16 Magic() const { return B_LENDIAN_TO_HOST_INT16(magic); }
uint16 State() const { return B_LENDIAN_TO_HOST_INT16(state); }
uint32 RevisionLevel() const { return B_LENDIAN_TO_HOST_INT16(revision_level); }
uint32 BlockShift() const { return B_LENDIAN_TO_HOST_INT32(block_shift) + 10; }
uint32 NumInodes() const { return B_LENDIAN_TO_HOST_INT32(num_inodes); }
uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); }
@ -106,6 +108,8 @@ struct ext2_super_block {
{ return B_LENDIAN_TO_HOST_INT32(read_only_features); }
uint32 IncompatibleFeatures() const
{ return B_LENDIAN_TO_HOST_INT32(incompatible_features); }
uint32 HashSeed(uint8 i) const
{ return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); }
bool IsValid();
// implemented in Volume.cpp
@ -114,6 +118,12 @@ struct ext2_super_block {
#define EXT2_OLD_REVISION 0
#define EXT2_DYNAMIC_REVISION 1
#define EXT2_MAX_REVISION EXT2_DYNAMIC_REVISION
#define EXT2_FS_STATE_VALID 1 // File system was cleanly unmounted
#define EXT2_FS_STATE_ERROR 2 // File system has errors
#define EXT2_FS_STATE_ORPHAN 3 // Orphans are being recovered
// compatible features
#define EXT2_FEATURE_DIRECTORY_PREALLOCATION 0x0001
#define EXT2_FEATURE_IMAGIC_INODES 0x0002
@ -249,6 +259,7 @@ struct ext2_inode {
#define EXT2_INODE_DO_NOT_COMPRESS 0x00000400
#define EXT2_INODE_COMPRESSION_ERROR 0x00000800
#define EXT2_INODE_BTREE 0x00001000
#define EXT2_INODE_INDEXED 0x00001000
#define EXT2_NAME_LENGTH 255
@ -308,7 +319,7 @@ struct ext2_xattr_header {
}
void Dump() const {
for (int i = 0; i < Length(); i++)
for (unsigned int i = 0; i < Length(); i++)
dprintf("%02x ", ((uint8 *)this)[i]);
dprintf("\n");
}
@ -347,7 +358,7 @@ struct ext2_xattr_entry {
}
void Dump(bool full=false) const {
for (int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++)
for (unsigned int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++)
dprintf("%02x ", ((uint8 *)this)[i]);
dprintf("\n");
}

View File

@ -8,12 +8,14 @@
#include <util/kernel_cpp.h>
#include <string.h>
#include <AutoDeleter.h>
#include <fs_cache.h>
#include <fs_info.h>
#include "AttributeIterator.h"
#include "DirectoryIterator.h"
#include "ext2.h"
#include "HTree.h"
#include "Inode.h"
@ -292,6 +294,7 @@ ext2_get_file_map(fs_volume* _volume, fs_vnode* _node, off_t offset,
if (size <= vecs[index - 1].length || offset >= inode->Size()) {
// We're done!
*_count = index;
TRACE("ext2_get_file_map for inode %ld\n", inode->ID());
return B_OK;
}
}
@ -316,13 +319,22 @@ ext2_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name,
if (status < B_OK)
return status;
DirectoryIterator iterator(directory);
HTree htree(volume, directory);
DirectoryIterator* iterator;
status = htree.Lookup(name, &iterator);
if (status != B_OK)
return status;
ObjectDeleter<DirectoryIterator> iteratorDeleter(iterator);
while (true) {
char buffer[B_FILE_NAME_LENGTH];
size_t length = sizeof(buffer);
status = iterator.GetNext(buffer, &length, _vnodeID);
status = iterator->GetNext(buffer, &length, _vnodeID);
if (status != B_OK)
return status;
TRACE("ext2_lookup() %s\n", buffer);
if (!strcmp(buffer, name))
break;