* cdda_read_dir() did not correctly report the number of entries put into

the dirent buffer. This fixes Rene's comment about "ls" entering an endless
  loop.
* It also didn't access the buffer passed in correctly if it came from userland.
* It now also fills in as many entries in the buffer as fit.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26861 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-08-07 14:29:12 +00:00
parent ed7c4a3e9a
commit df6394aee1
@@ -1672,11 +1672,10 @@ cdda_open_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
static status_t
cdda_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
struct dirent *dirent, size_t bufferSize, uint32 *_num)
struct dirent *buffer, size_t bufferSize, uint32 *_num)
{
Volume *volume = (Volume *)_volume->private_volume;
Inode *inode = (Inode *)_node->private_node;
status_t status = 0;
TRACE(("cdda_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld, num = %p\n", _node, _cookie, dirent, bufferSize,_num));
@@ -1690,48 +1689,62 @@ cdda_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
const char *name = NULL;
Inode *nextChildNode = NULL;
int nextState = cookie->state;
uint32 max = *_num;
uint32 count = 0;
switch (cookie->state) {
case ITERATION_STATE_DOT:
childNode = inode;
name = ".";
nextChildNode = volume->FirstEntry();
nextState = cookie->state + 1;
while (count < max && bufferSize > sizeof(dirent)) {
switch (cookie->state) {
case ITERATION_STATE_DOT:
childNode = inode;
name = ".";
nextChildNode = volume->FirstEntry();
nextState = cookie->state + 1;
break;
case ITERATION_STATE_DOT_DOT:
childNode = inode; // parent of the root node is the root node
name = "..";
nextChildNode = volume->FirstEntry();
nextState = cookie->state + 1;
break;
default:
childNode = cookie->current;
if (childNode) {
name = childNode->Name();
nextChildNode = childNode->Next();
}
break;
}
if (childNode == NULL) {
// we're at the end of the directory
break;
case ITERATION_STATE_DOT_DOT:
childNode = inode; // parent of the root node is the root node
name = "..";
nextChildNode = volume->FirstEntry();
nextState = cookie->state + 1;
break;
default:
childNode = cookie->current;
if (childNode) {
name = childNode->Name();
nextChildNode = childNode->Next();
}
}
struct dirent entry;
entry.d_dev = volume->FSVolume()->id;
entry.d_ino = childNode->ID();
entry.d_reclen = strlen(name) + sizeof(struct dirent);
if (entry.d_reclen > bufferSize) {
if (count == 0)
return ENOBUFS;
break;
}
if (user_memcpy(buffer, &entry, sizeof(struct dirent) - 1) != B_OK
|| user_strlcpy(buffer->d_name, name, bufferSize) < B_OK)
return B_BAD_ADDRESS;
buffer = (struct dirent*)((uint8*)buffer + entry.d_reclen);
bufferSize -= entry.d_reclen;
count++;
cookie->current = nextChildNode;
cookie->state = nextState;
}
if (!childNode) {
// we're at the end of the directory
*_num = 0;
return B_OK;
}
dirent->d_dev = volume->FSVolume()->id;
dirent->d_ino = inode->ID();
dirent->d_reclen = strlen(name) + sizeof(struct dirent);
if (dirent->d_reclen > bufferSize)
return ENOBUFS;
status = user_strlcpy(dirent->d_name, name, bufferSize);
if (status < B_OK)
return status;
cookie->current = nextChildNode;
cookie->state = nextState;
*_num = count;
return B_OK;
}