From 49a7b6198dcc0bdcbe285b078a4c98f7a9a6d554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 7 Aug 2008 14:23:44 +0000 Subject: [PATCH] * fix_dirent() now correctly handles buffers from userland. * dir_read() now takes into account that we may have read more than one dir entry, and calls fix_dirent() for each of them. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26859 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/fs/vfs.cpp | 42 ++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 2739c48efb..05d2feac64 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -5144,10 +5144,25 @@ dir_read(struct io_context* ioContext, struct file_descriptor *descriptor, } -static void -fix_dirent(struct vnode *parent, struct dirent *entry, - struct io_context* ioContext) +static status_t +fix_dirent(struct vnode *parent, struct dirent *userEntry, + struct io_context* ioContext, uint32* _length) { + char buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; + struct dirent* entry; + + if (IS_USER_ADDRESS(userEntry)) { + unsigned short length; + entry = (struct dirent*)buffer; + if (user_memcpy(&length, &userEntry->d_reclen, sizeof(length)) != B_OK + || user_memcpy(entry, userEntry, length) != B_OK) + return B_BAD_ADDRESS; + + } else + entry = userEntry; + + *_length = entry->d_reclen; + // set d_pdev and d_pino entry->d_pdev = parent->device; entry->d_pino = parent->id; @@ -5181,7 +5196,7 @@ fix_dirent(struct vnode *parent, struct dirent *entry, status_t status = get_vnode(entry->d_dev, entry->d_ino, &vnode, true, false); if (status != B_OK) - return; + return status; mutex_lock(&sVnodeCoveredByMutex); if (vnode->covered_by) { @@ -5192,6 +5207,12 @@ fix_dirent(struct vnode *parent, struct dirent *entry, put_vnode(vnode); } + + // copy back from userland buffer if needed + if (entry != userEntry) + return user_memcpy(userEntry, entry, sizeof(struct dirent) - 1); + + return B_OK; } @@ -5208,9 +5229,16 @@ dir_read(struct io_context* ioContext, struct vnode *vnode, void *cookie, return error; // we need to adjust the read dirents - if (*_count > 0) { - // XXX: Currently reading only one dirent is supported. Make this a loop! - fix_dirent(vnode, buffer, ioContext); + uint32 count = *_count; + if (count > 0) { + for (uint32 i = 0; i < count; i++) { + uint32 length; + error = fix_dirent(vnode, buffer, ioContext, &length); + if (error != B_OK) + return error; + + buffer = (struct dirent*)((uint8*)buffer + length); + } } return error;