* 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
This commit is contained in:
@@ -5144,10 +5144,25 @@ dir_read(struct io_context* ioContext, struct file_descriptor *descriptor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static status_t
|
||||||
fix_dirent(struct vnode *parent, struct dirent *entry,
|
fix_dirent(struct vnode *parent, struct dirent *userEntry,
|
||||||
struct io_context* ioContext)
|
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
|
// set d_pdev and d_pino
|
||||||
entry->d_pdev = parent->device;
|
entry->d_pdev = parent->device;
|
||||||
entry->d_pino = parent->id;
|
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,
|
status_t status = get_vnode(entry->d_dev, entry->d_ino, &vnode, true,
|
||||||
false);
|
false);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return;
|
return status;
|
||||||
|
|
||||||
mutex_lock(&sVnodeCoveredByMutex);
|
mutex_lock(&sVnodeCoveredByMutex);
|
||||||
if (vnode->covered_by) {
|
if (vnode->covered_by) {
|
||||||
@@ -5192,6 +5207,12 @@ fix_dirent(struct vnode *parent, struct dirent *entry,
|
|||||||
|
|
||||||
put_vnode(vnode);
|
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;
|
return error;
|
||||||
|
|
||||||
// we need to adjust the read dirents
|
// we need to adjust the read dirents
|
||||||
if (*_count > 0) {
|
uint32 count = *_count;
|
||||||
// XXX: Currently reading only one dirent is supported. Make this a loop!
|
if (count > 0) {
|
||||||
fix_dirent(vnode, buffer, ioContext);
|
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;
|
return error;
|
||||||
|
|||||||
Reference in New Issue
Block a user