libc: improve dup/dup2 in vfs_plugin
This patch replaces the naive dup2 implementation (that merely duplicated the context pointer) by the replication of the original FD state by re-opening the same file with the same flags and seek position. This prevents a potential double release of the VFS handle (the FD context). It also implements 'dup'. Fixes #3505 Fixes #3477
This commit is contained in:
parent
59c60b8031
commit
c8b7710e5d
|
@ -268,7 +268,7 @@ extern "C" int dup2(int libc_fd, int new_libc_fd)
|
||||||
close(new_libc_fd);
|
close(new_libc_fd);
|
||||||
|
|
||||||
new_fd = file_descriptor_allocator()->alloc(fd->plugin, 0, new_libc_fd);
|
new_fd = file_descriptor_allocator()->alloc(fd->plugin, 0, new_libc_fd);
|
||||||
new_fd->path(fd->fd_path);
|
|
||||||
/* new_fd->context must be assigned by the plugin implementing 'dup2' */
|
/* new_fd->context must be assigned by the plugin implementing 'dup2' */
|
||||||
return fd->plugin->dup2(fd, new_fd);
|
return fd->plugin->dup2(fd, new_fd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ class Libc::Vfs_plugin : public Plugin
|
||||||
|
|
||||||
int access(char const *, int) override;
|
int access(char const *, int) override;
|
||||||
int close(File_descriptor *) override;
|
int close(File_descriptor *) override;
|
||||||
|
File_descriptor *dup(File_descriptor *) override;
|
||||||
int dup2(File_descriptor *, File_descriptor *) override;
|
int dup2(File_descriptor *, File_descriptor *) override;
|
||||||
int fcntl(File_descriptor *, int, long) override;
|
int fcntl(File_descriptor *, int, long) override;
|
||||||
int fstat(File_descriptor *, struct stat *) override;
|
int fstat(File_descriptor *, struct stat *) override;
|
||||||
|
|
|
@ -425,11 +425,55 @@ int Libc::Vfs_plugin::close(File_descriptor *fd)
|
||||||
int Libc::Vfs_plugin::dup2(File_descriptor *fd,
|
int Libc::Vfs_plugin::dup2(File_descriptor *fd,
|
||||||
File_descriptor *new_fd)
|
File_descriptor *new_fd)
|
||||||
{
|
{
|
||||||
new_fd->context = fd->context;
|
Vfs::Vfs_handle *handle = nullptr;
|
||||||
|
|
||||||
|
typedef Vfs::Directory_service::Open_result Result;
|
||||||
|
|
||||||
|
if (VFS_THREAD_SAFE(_root_dir.open(fd->fd_path, fd->flags, &handle, _alloc))
|
||||||
|
!= Result::OPEN_OK) {
|
||||||
|
|
||||||
|
warning("dup2 failed for path ", fd->fd_path);
|
||||||
|
return Errno(EBADF);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle->seek(vfs_handle(fd)->seek());
|
||||||
|
handle->handler(&_response_handler);
|
||||||
|
|
||||||
|
new_fd->context = vfs_context(handle);
|
||||||
|
new_fd->flags = fd->flags;
|
||||||
|
new_fd->path(fd->fd_path);
|
||||||
|
|
||||||
return new_fd->libc_fd;
|
return new_fd->libc_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Libc::File_descriptor *Libc::Vfs_plugin::dup(File_descriptor *fd)
|
||||||
|
{
|
||||||
|
Vfs::Vfs_handle *handle = nullptr;
|
||||||
|
|
||||||
|
typedef Vfs::Directory_service::Open_result Result;
|
||||||
|
|
||||||
|
if (VFS_THREAD_SAFE(_root_dir.open(fd->fd_path, fd->flags, &handle, _alloc))
|
||||||
|
!= Result::OPEN_OK) {
|
||||||
|
|
||||||
|
warning("dup failed for path ", fd->fd_path);
|
||||||
|
errno = EBADF;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle->seek(vfs_handle(fd)->seek());
|
||||||
|
handle->handler(&_response_handler);
|
||||||
|
|
||||||
|
File_descriptor * const new_fd =
|
||||||
|
file_descriptor_allocator()->alloc(this, vfs_context(handle));
|
||||||
|
|
||||||
|
new_fd->flags = fd->flags;
|
||||||
|
new_fd->path(fd->fd_path);
|
||||||
|
|
||||||
|
return new_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Libc::Vfs_plugin::fstat(File_descriptor *fd, struct stat *buf)
|
int Libc::Vfs_plugin::fstat(File_descriptor *fd, struct stat *buf)
|
||||||
{
|
{
|
||||||
Vfs::Vfs_handle *handle = vfs_handle(fd);
|
Vfs::Vfs_handle *handle = vfs_handle(fd);
|
||||||
|
@ -990,13 +1034,11 @@ int Libc::Vfs_plugin::fcntl(File_descriptor *fd, int cmd, long arg)
|
||||||
file_descriptor_allocator()->alloc(this, 0);
|
file_descriptor_allocator()->alloc(this, 0);
|
||||||
if (!new_fd) return Errno(EMFILE);
|
if (!new_fd) return Errno(EMFILE);
|
||||||
|
|
||||||
new_fd->path(fd->fd_path);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use new allocated number as name of file descriptor
|
* Use new allocated number as name of file descriptor
|
||||||
* duplicate.
|
* duplicate.
|
||||||
*/
|
*/
|
||||||
if (dup2(fd, new_fd) == -1) {
|
if (Vfs_plugin::dup2(fd, new_fd) == -1) {
|
||||||
error("Plugin::fcntl: dup2 unexpectedly failed");
|
error("Plugin::fcntl: dup2 unexpectedly failed");
|
||||||
return Errno(EINVAL);
|
return Errno(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user