btrfs: Return more than a single dirent at a time in btrfs_read_dir().

* similar to what mmlr did in hrev45575 for bfs.
This commit is contained in:
Jerome Duval 2013-05-02 19:20:52 +02:00
parent 8a43cad2ef
commit 795f13d6f2
2 changed files with 52 additions and 22 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2011-2013, Jérôme Duval, korli@users.berlios.de.
* This file may be used under the terms of the MIT License.
*/
@ -52,14 +52,18 @@ status_t
DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
{
if (fOffset == 0) {
*_nameLength = 3;
strlcpy(name, "..", *_nameLength);
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) {
*_nameLength = 2;
strlcpy(name, ".", *_nameLength);
if (*_nameLength < 2)
return B_BUFFER_OVERFLOW;
*_nameLength = 1;
strlcpy(name, ".", *_nameLength + 1);
fOffset = 2;
if (fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) {
*_id = fInode->ID();
@ -85,12 +89,19 @@ DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
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());
memcpy(name, entry + 1, entry->NameLength());
name[entry->NameLength()] = '\0';
*_nameLength = 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);

View File

@ -520,22 +520,41 @@ btrfs_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
struct dirent *dirent, size_t bufferSize, uint32 *_num)
{
DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
size_t length = bufferSize;
ino_t id;
status_t status = iterator->GetNext(dirent->d_name, &length, &id);
if (status == B_ENTRY_NOT_FOUND) {
*_num = 0;
return B_OK;
} else if (status != B_OK)
return status;
Volume* volume = (Volume*)_volume->private_volume;
dirent->d_dev = volume->ID();
dirent->d_ino = id;
dirent->d_reclen = sizeof(struct dirent) + length;
*_num = 1;
uint32 maxCount = *_num;
uint32 count = 0;
while (count < maxCount && bufferSize > sizeof(struct dirent)) {
ino_t id;
size_t length = bufferSize - sizeof(struct dirent) + 1;
status_t status = iterator->GetNext(dirent->d_name, &length,
&id);
if (status == B_ENTRY_NOT_FOUND)
break;
if (status == B_BUFFER_OVERFLOW) {
// the remaining name buffer length was too small
if (count == 0)
return B_BUFFER_OVERFLOW;
break;
}
if (status != B_OK)
return status;
dirent->d_dev = volume->ID();
dirent->d_ino = id;
dirent->d_reclen = sizeof(struct dirent) + length;
bufferSize -= dirent->d_reclen;
dirent = (struct dirent*)((uint8*)dirent + dirent->d_reclen);
count++;
}
*_num = count;
return B_OK;
}