Skip to content

Commit 907774b

Browse files
authored
Merge branch 'develop' into vlad_chdir
2 parents 11b1224 + c3c1424 commit 907774b

File tree

2 files changed

+418
-5
lines changed

2 files changed

+418
-5
lines changed

src/safeposix/syscalls/fs_calls.rs

Lines changed: 158 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)