@@ -2230,7 +2230,44 @@ impl Cage {
22302230 0 //chdir has succeeded!;
22312231 }
22322232
2233- //------------------------------------DUP & DUP2 SYSCALLS------------------------------------
2233+ ///##------------------------------------DUP & DUP2 SYSCALLS------------------------------------
2234+ /// ## `dup_syscall`
2235+ ///
2236+ /// ### Description
2237+ /// This function duplicates a file descriptor. It creates a new file
2238+ /// descriptor that refers to the same open file description as the original file descriptor.
2239+ /// * Finding the Next Available File Descriptor: If `start_desc` is provided and it is already in use, the function
2240+ /// will continue searching for the next available file descriptor starting from `start_desc`. If no file
2241+ /// descriptors are available, it will return an error (`ENFILE`).
2242+ /// * If `fd` is equal to `start_fd`, the function returns `start_fd` as the new file
2243+ /// descriptor. This is because in this scenario, the original and new file descriptors would point to the same
2244+ /// file description.
2245+ /// * The `_dup2_helper` function is called to perform the actual file descriptor duplication, handling the
2246+ /// allocation of a new file descriptor, updating the file descriptor table, and incrementing the reference count
2247+ /// of the file object.
2248+ /// * The function modifies the global `filedescriptortable` array, adding a new entry for the
2249+ /// duplicated file descriptor. It also increments the reference count of the file object associated with the
2250+ /// original file descriptor.
2251+ /// * The `false` argument passed to `_dup2_helper` indicates that this call is from the `dup_syscall` function,
2252+ /// not the `dup2_syscall` function.
2253+ ///
2254+ /// ### Function Arguments
2255+ /// * `fd`: The original file descriptor to duplicate.
2256+ /// * `start_desc`: An optional starting file descriptor number. If provided, the new file descriptor will be
2257+ /// assigned the first available file descriptor number starting from this value. If not provided, it defaults to
2258+ /// `STARTINGFD`,which is the minimum designated file descriptor value for new file descriptors.
2259+ ///
2260+ /// ### Returns
2261+ /// * The new file descriptor on success.
2262+ /// * `EBADF`: If the original file descriptor is invalid.
2263+ /// * `ENFILE`: If there are no available file descriptors.
2264+ ///
2265+ /// ### Errors
2266+ /// * `EBADF(9)`: If the original file descriptor is invalid.
2267+ /// * `ENFILE(23)`: If there are no available file descriptors.
2268+ /// ###Panics
2269+ /// * There are no panics for this syscall
2270+ ///[dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)
22342271
22352272 pub fn dup_syscall ( & self , fd : i32 , start_desc : Option < i32 > ) -> i32 {
22362273 //if a starting fd was passed, then use that as the starting point, but
@@ -2245,7 +2282,11 @@ impl Cage {
22452282 } //if the file descriptors are equal, return the new one
22462283
22472284 // get the filedesc_enum
2248- let checkedfd = self . get_filedescriptor ( fd) . unwrap ( ) ;
2285+ // Attempt to get the file descriptor; handle error if it does not exist
2286+ let checkedfd = match self . get_filedescriptor ( fd) {
2287+ Ok ( fd) => fd,
2288+ Err ( _) => return syscall_error ( Errno :: EBADF , "dup" , "Invalid old file descriptor." ) ,
2289+ } ;
22492290 let filedesc_enum = checkedfd. write ( ) ;
22502291 let filedesc_enum = if let Some ( f) = & * filedesc_enum {
22512292 f
@@ -2257,6 +2298,34 @@ impl Cage {
22572298 return Self :: _dup2_helper ( & self , filedesc_enum, start_fd, false ) ;
22582299 }
22592300
2301+ /// ## `dup2_syscall`
2302+ ///
2303+ /// ### Description
2304+ /// This function implements the `dup2` system call, which duplicates a file descriptor and assigns it to a new file
2305+ /// descriptor number. If the new file descriptor already exists, it is closed before the duplication takes place.
2306+ /// * File Descriptor Reuse: If the new file descriptor (`newfd`) is already open, the function will first close the
2307+ /// existing file descriptor silently (without returning an error) before allocating a new file descriptor and
2308+ /// updating the file descriptor table.
2309+ /// * If `oldfd` and `newfd` are the same, the function returns `newfd` without closing it.
2310+ /// This is because in this scenario, the original and new file descriptors would already point to the same file
2311+ /// description.
2312+ /// * the global `filedescriptortable` array, replacing the entry for the
2313+ /// new file descriptor with a new entry for the duplicated file descriptor. It also increments the reference count of the
2314+ /// file object associated with the original file descriptor.
2315+ ///
2316+ /// ### Function Arguments
2317+ /// * `oldfd`: The original file descriptor to duplicate.
2318+ /// * `newfd`: The new file descriptor number to assign to the duplicated file descriptor.
2319+ ///
2320+ /// ### Returns
2321+ /// * The new file descriptor on success.
2322+ ///
2323+ /// ### Errors
2324+ /// * `EBADF(9)`: If the original file descriptor (`oldfd`) is invalid or the new file descriptor (`newfd`) number is out of range.
2325+ /// ###Panics
2326+ /// * There are no panics for this syscall
2327+ ///[dup2(2)](https://linux.die.net/man/2/dup2)
2328+
22602329 pub fn dup2_syscall ( & self , oldfd : i32 , newfd : i32 ) -> i32 {
22612330 //checking if the new fd is out of range
22622331 if newfd >= MAXFD || newfd < 0 {
@@ -2272,7 +2341,10 @@ impl Cage {
22722341 } //if the file descriptors are equal, return the new one
22732342
22742343 // get the filedesc_enum
2275- let checkedfd = self . get_filedescriptor ( oldfd) . unwrap ( ) ;
2344+ let checkedfd = match self . get_filedescriptor ( oldfd) {
2345+ Ok ( fd) => fd,
2346+ Err ( _) => return syscall_error ( Errno :: EBADF , "dup2" , "Invalid old file descriptor." ) ,
2347+ } ;
22762348 let filedesc_enum = checkedfd. write ( ) ;
22772349 let filedesc_enum = if let Some ( f) = & * filedesc_enum {
22782350 f
@@ -2284,6 +2356,41 @@ impl Cage {
22842356 return Self :: _dup2_helper ( & self , filedesc_enum, newfd, true ) ;
22852357 }
22862358
2359+ /// ## `_dup2_helper`
2360+ ///
2361+ /// ### Description
2362+ /// This helper function performs the actual file descriptor duplication process for both `dup` and `dup2` system calls.
2363+ /// It handles the allocation of a new file descriptor, updates the file descriptor table, and increments the reference count of the
2364+ /// associated file object.
2365+ /// * Duplication from `dup2_syscall`: If `fromdup2` is true, the function first closes the existing file descriptor
2366+ /// at `newfd` (if any) before allocating a new file descriptor and updating the file descriptor table.
2367+ /// * Duplication from `dup_syscall`: If `fromdup2` is false, the function allocates a new file descriptor, finds the
2368+ /// first available file descriptor number starting from `newfd`, and updates the file descriptor table.
2369+ /// * Reference Counting: The function increments the reference count of the file object associated with the original file
2370+ /// descriptor. This ensures that the file object is not deleted until all its associated file descriptors are closed.
2371+ /// * Socket Handling: For domain sockets, the function increments the reference count of both the send and receive pipes
2372+ /// associated with the socket.
2373+ /// * Stream Handling: Streams are not currently supported for duplication
2374+ /// * Unhandled File Types: If the file descriptor is associated with a file type that is not handled by the function (i.e.,
2375+ /// not a File, Pipe, Socket, or Stream), the function returns an error (`EACCES`).
2376+ /// * The function does not handle streams.
2377+ /// * Socket Handling: If the file descriptor is associated with a socket, the function handles domain sockets differently
2378+ /// by incrementing the reference count of both the send and receive pipes.
2379+ /// ### Function Arguments
2380+ /// * `self`: A reference to the `FsCalls` struct, which contains the file descriptor table and other system-related data.
2381+ /// * `filedesc_enum`: A reference to the `FileDescriptor` object representing the file descriptor to be duplicated.
2382+ /// * `newfd`: The new file descriptor number to assign to the duplicated file descriptor.
2383+ /// * `fromdup2`: A boolean flag indicating whether the call is from `dup2_syscall` (true) or `dup_syscall` (false).
2384+ ///
2385+ /// ### Returns
2386+ /// * The new file descriptor on success.
2387+ ///
2388+ /// ### Errors
2389+ /// * `ENFILE(23)`: If there are no available file descriptors.
2390+ /// * `EACCES(13)`: If the file descriptor cannot be duplicated.
2391+ /// ###Panics
2392+ /// * If the file descriptor is associated with a socket, and the inode does not match the file descriptor.
2393+
22872394 pub fn _dup2_helper ( & self , filedesc_enum : & FileDescriptor , newfd : i32 , fromdup2 : bool ) -> i32 {
22882395 let ( dupfd, mut dupfdguard) = if fromdup2 {
22892396 let mut fdguard = self . filedescriptortable [ newfd as usize ] . write ( ) ;
@@ -2301,6 +2408,8 @@ impl Cage {
23012408 } else {
23022409 let ( newdupfd, guardopt) = self . get_next_fd ( Some ( newfd) ) ;
23032410 if newdupfd < 0 {
2411+ // The function allocates a new file descriptor and updates the file descriptor table,
2412+ // handling the potential for file descriptor table overflow (resulting in an `ENFILE` error).
23042413 return syscall_error (
23052414 Errno :: ENFILE ,
23062415 "dup2_helper" ,
@@ -2319,6 +2428,8 @@ impl Cage {
23192428 //incrementing the ref count so that when close is executed on the dup'd file
23202429 //the original file does not get a negative ref count
23212430 match * inodeobj {
2431+ // increments the reference count of the file object associated with the original file descriptor
2432+ // to ensure that the file object is not deleted until all its associated file descriptors are closed.
23222433 Inode :: File ( ref mut normalfile_inode_obj) => {
23232434 normalfile_inode_obj. refcount += 1 ;
23242435 }
0 commit comments