* 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 static status_t
cdda_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie, 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; Volume *volume = (Volume *)_volume->private_volume;
Inode *inode = (Inode *)_node->private_node; 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)); TRACE(("cdda_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld, num = %p\n", _node, _cookie, dirent, bufferSize,_num));
@@ -1690,7 +1689,10 @@ cdda_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
const char *name = NULL; const char *name = NULL;
Inode *nextChildNode = NULL; Inode *nextChildNode = NULL;
int nextState = cookie->state; int nextState = cookie->state;
uint32 max = *_num;
uint32 count = 0;
while (count < max && bufferSize > sizeof(dirent)) {
switch (cookie->state) { switch (cookie->state) {
case ITERATION_STATE_DOT: case ITERATION_STATE_DOT:
childNode = inode; childNode = inode;
@@ -1713,25 +1715,36 @@ cdda_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
break; break;
} }
if (!childNode) { if (childNode == NULL) {
// we're at the end of the directory // we're at the end of the directory
*_num = 0; break;
return B_OK;
} }
dirent->d_dev = volume->FSVolume()->id; struct dirent entry;
dirent->d_ino = inode->ID(); entry.d_dev = volume->FSVolume()->id;
dirent->d_reclen = strlen(name) + sizeof(struct dirent); entry.d_ino = childNode->ID();
entry.d_reclen = strlen(name) + sizeof(struct dirent);
if (dirent->d_reclen > bufferSize) if (entry.d_reclen > bufferSize) {
if (count == 0)
return ENOBUFS; return ENOBUFS;
status = user_strlcpy(dirent->d_name, name, bufferSize); break;
if (status < B_OK) }
return status;
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->current = nextChildNode;
cookie->state = nextState; cookie->state = nextState;
}
*_num = count;
return B_OK; return B_OK;
} }