Implement F_DUPFD in fcntl
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user