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:
parent
8a43cad2ef
commit
795f13d6f2
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user