diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index ac2c9d06e7..193b1382d6 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -19,6 +19,7 @@ extern "C" { #endif struct dirent; +struct fd_info; struct fd_set; struct fs_info; struct iovec; @@ -180,7 +181,8 @@ extern ssize_t _kern_write(int fd, off_t pos, const void *buffer, size_t buffer extern ssize_t _kern_writev(int fd, off_t pos, const struct iovec *vecs, size_t count); extern status_t _kern_ioctl(int fd, ulong cmd, void *data, size_t length); -extern ssize_t _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, uint32 maxCount); +extern ssize_t _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, + uint32 maxCount); extern status_t _kern_rewind_dir(int fd); extern status_t _kern_read_stat(int fd, const char *path, bool traverseLink, struct stat *stat, size_t statSize); @@ -192,6 +194,8 @@ extern int _kern_dup(int fd); extern int _kern_dup2(int ofd, int nfd); extern status_t _kern_lock_node(int fd); extern status_t _kern_unlock_node(int fd); +extern status_t _kern_get_next_fd_info(team_id team, uint32 *_cookie, + struct fd_info *info, size_t infoSize); // node monitor functions extern status_t _kern_stop_notifying(port_id port, uint32 token); diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index 2a0d881004..e41536d9ed 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -43,6 +43,12 @@ typedef struct io_context { uint32 max_monitors; } io_context; +struct fd_info { + int number; + int32 open_mode; + dev_t device; + ino_t node; +}; /* macro to allocate a iovec array on the stack */ #define IOVECS(name, size) \ @@ -111,6 +117,8 @@ status_t _user_read_fs_info(dev_t device, struct fs_info *info); status_t _user_write_fs_info(dev_t device, const struct fs_info *info, int mask); dev_t _user_next_device(int32 *_cookie); status_t _user_sync(void); +status_t _user_get_next_fd_info(team_id team, uint32 *cookie, struct fd_info *info, + size_t infoSize); status_t _user_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf, char *userPath, size_t pathLength); int _user_open_entry_ref(dev_t device, ino_t inode, const char *name, int openMode, int perms); diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 4be41c875e..eee6eb6749 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -5561,6 +5561,73 @@ _kern_next_device(int32 *_cookie) } +status_t +_kern_get_next_fd_info(team_id teamID, uint32 *_cookie, fd_info *info, + size_t infoSize) +{ + if (infoSize != sizeof(fd_info)) + return B_BAD_VALUE; + + struct io_context *context = NULL; + sem_id contextMutex = -1; + struct team *team = NULL; + + cpu_status state = disable_interrupts(); + GRAB_TEAM_LOCK(); + + team = team_get_team_struct_locked(teamID); + if (team) { + context = (io_context *)team->io_context; + contextMutex = context->io_mutex.sem; + } + + RELEASE_TEAM_LOCK(); + restore_interrupts(state); + + // we now have a context - since we couldn't lock it while having + // safe access to the team structure, we now need to lock the mutex + // manually + + if (context == NULL || acquire_sem(contextMutex) != B_OK) { + // team doesn't exit or seems to be gone + return B_BAD_TEAM_ID; + } + + // the team cannot be deleted completely while we're owning its + // io_context mutex, so we can safely play with it now + + context->io_mutex.holder = thread_get_current_thread_id(); + + uint32 slot = *_cookie; + + struct file_descriptor *descriptor; + while (slot < context->table_size && (descriptor = context->fds[slot]) == NULL) + slot++; + + if (slot >= context->table_size) { + mutex_unlock(&context->io_mutex); + return B_ENTRY_NOT_FOUND; + } + + info->number = slot; + info->open_mode = descriptor->open_mode; + + struct vnode *vnode = fd_vnode(descriptor); + if (vnode != NULL) { + info->device = vnode->device; + info->node = vnode->id; + } else if (descriptor->u.mount != NULL) { + info->device = descriptor->u.mount->id; + info->node = -1; + } + + mutex_unlock(&context->io_mutex); + + *_cookie = slot + 1; + return B_OK; +} + + int _kern_open_entry_ref(dev_t device, ino_t inode, const char *name, int openMode, int perms) { @@ -6272,6 +6339,32 @@ _user_sync(void) } +status_t +_user_get_next_fd_info(team_id team, uint32 *userCookie, fd_info *userInfo, + size_t infoSize) +{ + struct fd_info info; + uint32 cookie; + + if (infoSize != sizeof(fd_info)) + return B_BAD_VALUE; + + if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo) + || user_memcpy(&cookie, userCookie, sizeof(uint32)) < B_OK) + return B_BAD_ADDRESS; + + status_t status = _kern_get_next_fd_info(team, &cookie, &info, infoSize); + if (status < B_OK) + return status; + + if (user_memcpy(userCookie, &cookie, sizeof(uint32)) < B_OK + || user_memcpy(userInfo, &info, infoSize) < B_OK) + return B_BAD_ADDRESS; + + return status; +} + + status_t _user_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf, char *userPath, size_t pathLength)