From 96fe0378b7c183aebb4ba27743ba2e9843fcdd8a Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Sun, 11 Jan 2026 22:05:47 -0800 Subject: [PATCH] implement F_DUPFD for sys_fcntl --- src/process/fd_table.rs | 27 +++++++++++++++++++++++++-- src/process/fd_table/dup.rs | 15 ++++++++++++--- src/process/fd_table/fcntl.rs | 6 +++--- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/process/fd_table.rs b/src/process/fd_table.rs index 2f11172..eda2471 100644 --- a/src/process/fd_table.rs +++ b/src/process/fd_table.rs @@ -88,8 +88,8 @@ impl FileDescriptorTable { Ok(fd) } - // Insert the given etnry at the specified index. If there was an entry at - // that index `Some(entry)` is returned. Otherwise, `None` is returned. + /// Insert the given entry at the specified index. If there was an entry at + /// that index `Some(entry)` is returned. Otherwise, `None` is returned. fn insert_at(&mut self, fd: Fd, entry: FileDescriptorEntry) -> Option { let fd_idx = fd.0 as usize; @@ -101,6 +101,29 @@ impl FileDescriptorTable { self.entries[fd_idx].replace(entry) } + /// Insert the given entry at or above the specified index, returning the + /// file descriptor used. + fn insert_above(&mut self, min_fd: Fd, file: Arc) -> Result { + let start_idx = min_fd.0 as usize; + let entry = FileDescriptorEntry { + file, + flags: FdFlags::default(), + }; + + for i in start_idx..self.entries.len() { + if self.entries[i].is_none() { + let fd = Fd(i as i32); + self.insert_at(fd, entry); + return Ok(fd); + } + } + + // No free slot found, so we need to expand the table. + let fd = Fd(self.entries.len() as i32); + self.entries.push(Some(entry)); + Ok(fd) + } + /// Removes a file descriptor from the table, returning the file if it /// existed. pub fn remove(&mut self, fd: Fd) -> Option> { diff --git a/src/process/fd_table/dup.rs b/src/process/fd_table/dup.rs index 22b38fd..b879e60 100644 --- a/src/process/fd_table/dup.rs +++ b/src/process/fd_table/dup.rs @@ -6,13 +6,22 @@ use libkernel::{ use super::{Fd, FdFlags, FileDescriptorEntry}; -pub fn sys_dup(fd: Fd) -> Result { +pub fn dup_fd(fd: Fd, min_fd: Option) -> Result { let task = current_task(); let mut files = task.fd_table.lock_save_irq(); - let fd = files.get(fd).ok_or(KernelError::BadFd)?; + let file = files.get(fd).ok_or(KernelError::BadFd)?; - let new_fd = files.insert(fd.clone())?; + let new_fd = match min_fd { + Some(min_fd) => files.insert_above(min_fd, file.clone())?, + None => files.insert(file.clone())?, + }; + + Ok(new_fd) +} + +pub fn sys_dup(fd: Fd) -> Result { + let new_fd = dup_fd(fd, None)?; Ok(new_fd.as_raw() as _) } diff --git a/src/process/fd_table/fcntl.rs b/src/process/fd_table/fcntl.rs index 0ffe3f4..f3d08b0 100644 --- a/src/process/fd_table/fcntl.rs +++ b/src/process/fd_table/fcntl.rs @@ -1,9 +1,9 @@ use bitflags::Flags; use libkernel::error::{KernelError, Result}; -use crate::{process::fd_table::FdFlags, sched::current::current_task_shared}; - use super::Fd; +use crate::process::fd_table::dup::dup_fd; +use crate::{process::fd_table::FdFlags, sched::current::current_task_shared}; const F_DUPFD: u32 = 0; // Duplicate file descriptor. const F_GETFD: u32 = 1; // Get file descriptor flags. @@ -15,7 +15,7 @@ pub async fn sys_fcntl(fd: Fd, op: u32, arg: usize) -> Result { let task = current_task_shared(); match op { - F_DUPFD => todo!(), + F_DUPFD => dup_fd(fd, Some(Fd(arg as i32))).map(|new_fd| new_fd.as_raw() as _), F_GETFD => { let fds = task.fd_table.lock_save_irq(); let fd = fds