From df6394aee14a68847ef69d67e77db45ef02d0003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 7 Aug 2008 14:29:12 +0000 Subject: [PATCH] * 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 --- .../file_systems/cdda/kernel_interface.cpp | 91 +++++++++++-------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp b/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp index 71c4d5c0a1..d8701421e3 100644 --- a/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/cdda/kernel_interface.cpp @@ -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; }