From 1623baa137adcb7e7c4944ce365692519b292b3a Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott <ian@iandouglasscott.com> Date: Tue, 8 Aug 2017 10:59:11 -0700 Subject: [PATCH] Implement F_DUPFD in fcntl --- src/context/context.rs | 17 ++++++++++++++--- src/syscall/fs.rs | 20 +++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/context/context.rs b/src/context/context.rs index 56e3e10f..1cf5a900 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -244,17 +244,28 @@ impl Context { /// Add a file to the lowest available slot. /// Return the file descriptor number or None if no slot was found pub fn add_file(&self, file: FileDescriptor) -> Option<FileHandle> { + self.add_file_min(file, 0) + } + + /// Add a file to the lowest available slot greater than or equal to min. + /// Return the file descriptor number or None if no slot was found + pub fn add_file_min(&self, file: FileDescriptor, min: usize) -> Option<FileHandle> { let mut files = self.files.lock(); for (i, mut file_option) in files.iter_mut().enumerate() { - if file_option.is_none() { + if file_option.is_none() && i >= min { *file_option = Some(file); return Some(FileHandle::from(i)); } } let len = files.len(); if len < super::CONTEXT_MAX_FILES { - files.push(Some(file)); - Some(FileHandle::from(len)) + if len >= min { + files.push(Some(file)); + Some(FileHandle::from(len)) + } else { + drop(files); + self.insert_file(FileHandle::from(min), file) + } } else { None } diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index 1de6cedc..168d165c 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -8,7 +8,7 @@ use scheme::{self, FileHandle}; use syscall; use syscall::data::{Packet, Stat}; use syscall::error::*; -use syscall::flag::{F_GETFD, F_SETFD, F_GETFL, F_SETFL, O_ACCMODE, O_RDONLY, O_WRONLY, MODE_DIR, MODE_FILE, O_CLOEXEC}; +use syscall::flag::{F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_DUPFD, O_ACCMODE, O_RDONLY, O_WRONLY, MODE_DIR, MODE_FILE, O_CLOEXEC}; use context::file::{FileDescriptor, FileDescription}; pub fn file_op(a: usize, fd: FileHandle, c: usize, d: usize) -> Result<usize> { @@ -287,7 +287,7 @@ pub fn dup(fd: FileHandle, buf: &[u8]) -> Result<FileHandle> { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - + context.add_file(new_file).ok_or(Error::new(EMFILE)) } @@ -320,7 +320,7 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> { let description = file.description.read(); // Communicate fcntl with scheme - if cmd != F_GETFD && cmd != F_SETFD { + if cmd != F_DUPFD && cmd != F_GETFD && cmd != F_SETFD { let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(description.scheme).ok_or(Error::new(EBADF))?; @@ -331,9 +331,23 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> { // Perform kernel operation if scheme agrees { + if cmd == F_DUPFD { + // Not in match because 'files' cannot be locked + let new_file = duplicate_file(fd, &[])?; + + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + + return context.add_file_min(new_file, arg) + .ok_or(Error::new(EMFILE)) + .map(FileHandle::into); + } + let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); + let mut files = context.files.lock(); match *files.get_mut(fd.into()).ok_or(Error::new(EBADF))? { Some(ref mut file) => match cmd { -- GitLab