* Copyright 2017, ChαΊΏ VΕ© Gia Hy, cvghy116@gmail.com.
* Copyright 2011-2013, JΓ©rΓ΄me Duval, korli@users.berlios.de.
* This file may be used under the terms of the MIT License.
*/
#include "DirectoryIterator.h"
#include "CRCTable.h"
#ifdef TRACE_BTRFS
# define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
#else
# define TRACE(x...) ;
#endif
# define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
DirectoryIterator::DirectoryIterator(Inode* inode)
:
fOffset(0),
fInode(inode),
fIterator(NULL)
{
btrfs_key key;
key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
key.SetObjectID(inode->ID());
key.SetOffset(BTREE_BEGIN);
fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(),
key);
}
DirectoryIterator::~DirectoryIterator()
{
delete fIterator;
fIterator = NULL;
}
status_t
DirectoryIterator::InitCheck()
{
return fIterator != NULL ? B_OK : B_NO_MEMORY;
}
status_t
DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
{
if (fOffset == 0) {
if (*_nameLength < 3)
return B_BUFFER_OVERFLOW;
*_nameLength = 2;
strlcpy(name, "..", *_nameLength + 1);
*_id = fInode->ID();
fOffset = 1;
return B_OK;
} else if (fOffset == 1) {
if (*_nameLength < 2)
return B_BUFFER_OVERFLOW;
*_nameLength = 1;
strlcpy(name, ".", *_nameLength + 1);
fOffset = 2;
if (fInode->ID() == BTRFS_FIRST_SUBVOLUME) {
*_id = fInode->ID();
return B_OK;
}
return fInode->FindParent(_id);
}
btrfs_dir_entry* entries;
uint32 entries_length;
status_t status = fIterator->GetNextEntry((void**)&entries, &entries_length);
if (status != B_OK)
return status;
btrfs_dir_entry* entry = entries;
uint16 current = 0;
while (current < entries_length) {
current += entry->Length();
break;
entry = (btrfs_dir_entry*)((uint8*)entry + entry->Length());
}
size_t length = entry->NameLength();
TRACE("DirectoryIterator::GetNext() entries_length %ld name_length %d\n",
entries_length, entry->NameLength());
if (length + 1 > *_nameLength) {
free(entries);
return B_BUFFER_OVERFLOW;
}
memcpy(name, entry + 1, length);
name[length] = '\0';
*_nameLength = length;
*_id = entry->InodeID();
free(entries);
return B_OK;
}
status_t
DirectoryIterator::Lookup(const char* name, size_t nameLength, ino_t* _id)
{
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
if (strcmp(name, ".") == 0
|| fInode->ID() == BTRFS_FIRST_SUBVOLUME) {
*_id = fInode->ID();
return B_OK;
}
return fInode->FindParent(_id);
}
uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength);
btrfs_key key;
key.SetType(BTRFS_KEY_TYPE_DIR_ITEM);
key.SetObjectID(fInode->ID());
key.SetOffset(hash);
BTree::Path path(fInode->GetVolume()->FSTree());
btrfs_dir_entry* entries;
uint32 length;
status_t status = fInode->GetVolume()->FSTree()->FindExact(&path, key,
(void**)&entries, &length);
if (status != B_OK) {
TRACE("DirectoryIterator::Lookup(): Couldn't find entry with hash %" B_PRIu32
" \"%s\"\n", hash, name);
return status;
}
btrfs_dir_entry* entry = entries;
uint16 current = 0;
while (current < length) {
current += entry->Length();
break;
entry = (btrfs_dir_entry*)((uint8*)entry + entry->Length());
}
TRACE("DirectoryIterator::Lookup() entries_length %ld name_length %d\n",
length, entry->NameLength());
*_id = entry->InodeID();
free(entries);
return B_OK;
}
status_t
DirectoryIterator::Rewind()
{
fIterator->Rewind();
fOffset = BTREE_BEGIN;
return B_OK;
}