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:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011, Jérôme Duval, [email protected].
|
* Copyright 2011-2013, Jérôme Duval, [email protected].
|
||||||
* This file may be used under the terms of the MIT License.
|
* 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)
|
DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id)
|
||||||
{
|
{
|
||||||
if (fOffset == 0) {
|
if (fOffset == 0) {
|
||||||
*_nameLength = 3;
|
if (*_nameLength < 3)
|
||||||
strlcpy(name, "..", *_nameLength);
|
return B_BUFFER_OVERFLOW;
|
||||||
|
*_nameLength = 2;
|
||||||
|
strlcpy(name, "..", *_nameLength + 1);
|
||||||
*_id = fInode->ID();
|
*_id = fInode->ID();
|
||||||
fOffset = 1;
|
fOffset = 1;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
} else if (fOffset == 1) {
|
} else if (fOffset == 1) {
|
||||||
*_nameLength = 2;
|
if (*_nameLength < 2)
|
||||||
strlcpy(name, ".", *_nameLength);
|
return B_BUFFER_OVERFLOW;
|
||||||
|
*_nameLength = 1;
|
||||||
|
strlcpy(name, ".", *_nameLength + 1);
|
||||||
fOffset = 2;
|
fOffset = 2;
|
||||||
if (fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) {
|
if (fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) {
|
||||||
*_id = fInode->ID();
|
*_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());
|
entry = (btrfs_dir_entry *)((uint8*)entry + entry->Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t length = entry->NameLength();
|
||||||
|
|
||||||
TRACE("DirectoryIterator::GetNext() entries_length %ld name_length %d\n",
|
TRACE("DirectoryIterator::GetNext() entries_length %ld name_length %d\n",
|
||||||
entries_length, entry->NameLength());
|
entries_length, entry->NameLength());
|
||||||
|
|
||||||
memcpy(name, entry + 1, entry->NameLength());
|
if (length + 1 > *_nameLength) {
|
||||||
name[entry->NameLength()] = '\0';
|
free(entries);
|
||||||
*_nameLength = entry->NameLength();
|
return B_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(name, entry + 1, length);
|
||||||
|
name[length] = '\0';
|
||||||
|
*_nameLength = length;
|
||||||
*_id = entry->InodeID();
|
*_id = entry->InodeID();
|
||||||
free(entries);
|
free(entries);
|
||||||
|
|
||||||
|
|||||||
@@ -520,22 +520,41 @@ btrfs_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
|
|||||||
struct dirent *dirent, size_t bufferSize, uint32 *_num)
|
struct dirent *dirent, size_t bufferSize, uint32 *_num)
|
||||||
{
|
{
|
||||||
DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
|
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;
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user