@@ -2308,7 +2308,44 @@ impl Cage {
23082308 }
23092309 }
23102310
2311- //------------------------------------DUP & DUP2 SYSCALLS------------------------------------
2311+ ///##------------------------------------DUP & DUP2 SYSCALLS------------------------------------
2312+ /// ## `dup_syscall`
2313+ ///
2314+ /// ### Description
2315+ /// This function duplicates a file descriptor. It creates a new file
2316+ /// descriptor that refers to the same open file description as the original file descriptor.
2317+ /// * Finding the Next Available File Descriptor: If `start_desc` is provided and it is already in use, the function
2318+ /// will continue searching for the next available file descriptor starting from `start_desc`. If no file
2319+ /// descriptors are available, it will return an error (`ENFILE`).
2320+ /// * If `fd` is equal to `start_fd`, the function returns `start_fd` as the new file
2321+ /// descriptor. This is because in this scenario, the original and new file descriptors would point to the same
2322+ /// file description.
2323+ /// * The `_dup2_helper` function is called to perform the actual file descriptor duplication, handling the
2324+ /// allocation of a new file descriptor, updating the file descriptor table, and incrementing the reference count
2325+ /// of the file object.
2326+ /// * The function modifies the global `filedescriptortable` array, adding a new entry for the
2327+ /// duplicated file descriptor. It also increments the reference count of the file object associated with the
2328+ /// original file descriptor.
2329+ /// * The `false` argument passed to `_dup2_helper` indicates that this call is from the `dup_syscall` function,
2330+ /// not the `dup2_syscall` function.
2331+ ///
2332+ /// ### Function Arguments
2333+ /// * `fd`: The original file descriptor to duplicate.
2334+ /// * `start_desc`: An optional starting file descriptor number. If provided, the new file descriptor will be
2335+ /// assigned the first available file descriptor number starting from this value. If not provided, it defaults to
2336+ /// `STARTINGFD`,which is the minimum designated file descriptor value for new file descriptors.
2337+ ///
2338+ /// ### Returns
2339+ /// * The new file descriptor on success.
2340+ /// * `EBADF`: If the original file descriptor is invalid.
2341+ /// * `ENFILE`: If there are no available file descriptors.
2342+ ///
2343+ /// ### Errors
2344+ /// * `EBADF(9)`: If the original file descriptor is invalid.
2345+ /// * `ENFILE(23)`: If there are no available file descriptors.
2346+ /// ###Panics
2347+ /// * There are no panics for this syscall
2348+ ///[dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)
23122349
23132350 pub fn dup_syscall ( & self , fd : i32 , start_desc : Option < i32 > ) -> i32 {
23142351 //if a starting fd was passed, then use that as the starting point, but
@@ -2323,7 +2360,11 @@ impl Cage {
23232360 } //if the file descriptors are equal, return the new one
23242361
23252362 // get the filedesc_enum
2326- let checkedfd = self . get_filedescriptor ( fd) . unwrap ( ) ;
2363+ // Attempt to get the file descriptor; handle error if it does not exist
2364+ let checkedfd = match self . get_filedescriptor ( fd) {
2365+ Ok ( fd) => fd,
2366+ Err ( _) => return syscall_error ( Errno :: EBADF , "dup" , "Invalid old file descriptor." ) ,
2367+ } ;
23272368 let filedesc_enum = checkedfd. write ( ) ;
23282369 let filedesc_enum = if let Some ( f) = & * filedesc_enum {
23292370 f
@@ -2335,6 +2376,34 @@ impl Cage {
23352376 return Self :: _dup2_helper ( & self , filedesc_enum, start_fd, false ) ;
23362377 }
23372378
2379+ /// ## `dup2_syscall`
2380+ ///
2381+ /// ### Description
2382+ /// This function implements the `dup2` system call, which duplicates a file descriptor and assigns it to a new file
2383+ /// descriptor number. If the new file descriptor already exists, it is closed before the duplication takes place.
2384+ /// * File Descriptor Reuse: If the new file descriptor (`newfd`) is already open, the function will first close the
2385+ /// existing file descriptor silently (without returning an error) before allocating a new file descriptor and
2386+ /// updating the file descriptor table.
2387+ /// * If `oldfd` and `newfd` are the same, the function returns `newfd` without closing it.
2388+ /// This is because in this scenario, the original and new file descriptors would already point to the same file
2389+ /// description.
2390+ /// * the global `filedescriptortable` array, replacing the entry for the
2391+ /// new file descriptor with a new entry for the duplicated file descriptor. It also increments the reference count of the
2392+ /// file object associated with the original file descriptor.
2393+ ///
2394+ /// ### Function Arguments
2395+ /// * `oldfd`: The original file descriptor to duplicate.
2396+ /// * `newfd`: The new file descriptor number to assign to the duplicated file descriptor.
2397+ ///
2398+ /// ### Returns
2399+ /// * The new file descriptor on success.
2400+ ///
2401+ /// ### Errors
2402+ /// * `EBADF(9)`: If the original file descriptor (`oldfd`) is invalid or the new file descriptor (`newfd`) number is out of range.
2403+ /// ###Panics
2404+ /// * There are no panics for this syscall
2405+ ///[dup2(2)](https://linux.die.net/man/2/dup2)
2406+
23382407 pub fn dup2_syscall ( & self , oldfd : i32 , newfd : i32 ) -> i32 {
23392408 //checking if the new fd is out of range
23402409 if newfd >= MAXFD || newfd < 0 {
@@ -2350,7 +2419,10 @@ impl Cage {
23502419 } //if the file descriptors are equal, return the new one
23512420
23522421 // get the filedesc_enum
2353- let checkedfd = self . get_filedescriptor ( oldfd) . unwrap ( ) ;
2422+ let checkedfd = match self . get_filedescriptor ( oldfd) {
2423+ Ok ( fd) => fd,
2424+ Err ( _) => return syscall_error ( Errno :: EBADF , "dup2" , "Invalid old file descriptor." ) ,
2425+ } ;
23542426 let filedesc_enum = checkedfd. write ( ) ;
23552427 let filedesc_enum = if let Some ( f) = & * filedesc_enum {
23562428 f
@@ -2362,6 +2434,41 @@ impl Cage {
23622434 return Self :: _dup2_helper ( & self , filedesc_enum, newfd, true ) ;
23632435 }
23642436
2437+ /// ## `_dup2_helper`
2438+ ///
2439+ /// ### Description
2440+ /// This helper function performs the actual file descriptor duplication process for both `dup` and `dup2` system calls.
2441+ /// It handles the allocation of a new file descriptor, updates the file descriptor table, and increments the reference count of the
2442+ /// associated file object.
2443+ /// * Duplication from `dup2_syscall`: If `fromdup2` is true, the function first closes the existing file descriptor
2444+ /// at `newfd` (if any) before allocating a new file descriptor and updating the file descriptor table.
2445+ /// * Duplication from `dup_syscall`: If `fromdup2` is false, the function allocates a new file descriptor, finds the
2446+ /// first available file descriptor number starting from `newfd`, and updates the file descriptor table.
2447+ /// * Reference Counting: The function increments the reference count of the file object associated with the original file
2448+ /// descriptor. This ensures that the file object is not deleted until all its associated file descriptors are closed.
2449+ /// * Socket Handling: For domain sockets, the function increments the reference count of both the send and receive pipes
2450+ /// associated with the socket.
2451+ /// * Stream Handling: Streams are not currently supported for duplication
2452+ /// * Unhandled File Types: If the file descriptor is associated with a file type that is not handled by the function (i.e.,
2453+ /// not a File, Pipe, Socket, or Stream), the function returns an error (`EACCES`).
2454+ /// * The function does not handle streams.
2455+ /// * Socket Handling: If the file descriptor is associated with a socket, the function handles domain sockets differently
2456+ /// by incrementing the reference count of both the send and receive pipes.
2457+ /// ### Function Arguments
2458+ /// * `self`: A reference to the `FsCalls` struct, which contains the file descriptor table and other system-related data.
2459+ /// * `filedesc_enum`: A reference to the `FileDescriptor` object representing the file descriptor to be duplicated.
2460+ /// * `newfd`: The new file descriptor number to assign to the duplicated file descriptor.
2461+ /// * `fromdup2`: A boolean flag indicating whether the call is from `dup2_syscall` (true) or `dup_syscall` (false).
2462+ ///
2463+ /// ### Returns
2464+ /// * The new file descriptor on success.
2465+ ///
2466+ /// ### Errors
2467+ /// * `ENFILE(23)`: If there are no available file descriptors.
2468+ /// * `EACCES(13)`: If the file descriptor cannot be duplicated.
2469+ /// ###Panics
2470+ /// * If the file descriptor is associated with a socket, and the inode does not match the file descriptor.
2471+
23652472 pub fn _dup2_helper ( & self , filedesc_enum : & FileDescriptor , newfd : i32 , fromdup2 : bool ) -> i32 {
23662473 let ( dupfd, mut dupfdguard) = if fromdup2 {
23672474 let mut fdguard = self . filedescriptortable [ newfd as usize ] . write ( ) ;
@@ -2379,6 +2486,8 @@ impl Cage {
23792486 } else {
23802487 let ( newdupfd, guardopt) = self . get_next_fd ( Some ( newfd) ) ;
23812488 if newdupfd < 0 {
2489+ // The function allocates a new file descriptor and updates the file descriptor table,
2490+ // handling the potential for file descriptor table overflow (resulting in an `ENFILE` error).
23822491 return syscall_error (
23832492 Errno :: ENFILE ,
23842493 "dup2_helper" ,
@@ -2397,6 +2506,8 @@ impl Cage {
23972506 //incrementing the ref count so that when close is executed on the dup'd file
23982507 //the original file does not get a negative ref count
23992508 match * inodeobj {
2509+ // increments the reference count of the file object associated with the original file descriptor
2510+ // to ensure that the file object is not deleted until all its associated file descriptors are closed.
24002511 Inode :: File ( ref mut normalfile_inode_obj) => {
24012512 normalfile_inode_obj. refcount += 1 ;
24022513 }
@@ -3888,16 +3999,56 @@ impl Cage {
38883999 }
38894000
38904001 //------------------GETDENTS SYSCALL------------------
4002+ /// ## `getdents_syscall`
4003+ ///
4004+ /// ### Description
4005+ /// This function reads directory entries from a directory file descriptor
4006+ /// and returns them in a buffer. Reading directory entries using multiple read calls can be less efficient because it
4007+ /// involves reading the data in smaller chunks and then parsing it.
4008+ /// getdents can often be faster by reading directory entries in a more optimized way.
4009+ /// * The function first checks if the provided buffer size is sufficient to store at least one
4010+ /// `ClippedDirent` structure.
4011+ /// * The function validates the provided file descriptor to ensure it represents a
4012+ /// valid file.
4013+ /// * The function checks if the file descriptor refers to a directory.
4014+ /// * The function iterates over the directory entries in the
4015+ /// `filename_to_inode_dict` of the directory inode.
4016+ /// * For each entry, the function constructs a `ClippedDirent` structure, which
4017+ /// contains the inode number, offset, and record length.
4018+ /// * It packs the constructed directory entries into the provided buffer (`dirp`).
4019+ /// * Updates the file position to the next directory entry to be read.
4020+ ///
4021+ /// ### Function Arguments
4022+ /// * `fd`: A file descriptor representing the directory to read.
4023+ /// * `dirp`: A pointer to a buffer where the directory entries will be written.
4024+ /// * `bufsize`: The size of the buffer in bytes.
4025+ ///
4026+ /// ### Returns
4027+ /// * The number of bytes written to the buffer on success.
4028+ ///
4029+ /// ### Errors
4030+ /// * `EINVAL(22)`: If the buffer size is too small or if the file descriptor is invalid.
4031+ /// * `ENOTDIR(20)`: If the file descriptor does not refer to a existing directory.
4032+ /// * `ESPIPE(29)`: If the file descriptor does not refer to a file.
4033+ /// * `EBADF(9)` : If the file descriptor is invalid.
4034+ /// ### Panics
4035+ /// * There are no panics in this syscall.
38914036
38924037 pub fn getdents_syscall ( & self , fd : i32 , dirp : * mut u8 , bufsize : u32 ) -> i32 {
38934038 let mut vec: Vec < ( interface:: ClippedDirent , Vec < u8 > ) > = Vec :: new ( ) ;
38944039
38954040 // make sure bufsize is at least greater than size of a ClippedDirent struct
4041+ // ClippedDirent is a simplified version of the traditional dirent structure used in POSIX systems
4042+ // By using a simpler structure, SafePosix can store and retrieve directory entries more efficiently,
4043+ // potentially improving performance compared to using the full dirent structure.
38964044 if bufsize <= interface:: CLIPPED_DIRENT_SIZE {
38974045 return syscall_error ( Errno :: EINVAL , "getdents" , "Result buffer is too small." ) ;
38984046 }
38994047
3900- let checkedfd = self . get_filedescriptor ( fd) . unwrap ( ) ;
4048+ let checkedfd = match self . get_filedescriptor ( fd) {
4049+ Ok ( fd) => fd,
4050+ Err ( _) => return syscall_error ( Errno :: EBADF , "getdents" , "Invalid file descriptor." ) ,
4051+ } ;
39014052 let mut unlocked_fd = checkedfd. write ( ) ;
39024053 if let Some ( filedesc_enum) = & mut * unlocked_fd {
39034054 match filedesc_enum {
@@ -3927,7 +4078,7 @@ impl Cage {
39274078 // convert filename to a filename vector of u8
39284079 let mut vec_filename: Vec < u8 > = filename. as_bytes ( ) . to_vec ( ) ;
39294080 vec_filename. push ( b'\0' ) ; // make filename null-terminated
3930-
4081+ // Push DT_UNKNOWN as d_type. This is a placeholder for now, as the actual file type is not yet determined.
39314082 vec_filename. push ( DT_UNKNOWN ) ; // push DT_UNKNOWN as d_type (for now)
39324083 temp_len =
39334084 interface:: CLIPPED_DIRENT_SIZE + vec_filename. len ( ) as u32 ; // get length of current filename vector for padding calculation
@@ -3963,6 +4114,8 @@ impl Cage {
39634114 count += 1 ;
39644115 }
39654116 // update file position
4117+ // keeps track of the current position within the directory. It indicates which directory entry the
4118+ // function should read next.
39664119 normalfile_filedesc_obj. position = interface:: rust_min (
39674120 position + count,
39684121 dir_inode_obj. filename_to_inode_dict . len ( ) ,
0 commit comments