Skip to content

Commit 9ec2078

Browse files
rupeshkoushik07lind
authored andcommitted
Update getdents_syscall tests and comments (#286)
* add tests and comments * change sem comment * update * update comments * update tests * update format * update format
1 parent 5223a15 commit 9ec2078

File tree

2 files changed

+175
-4
lines changed

2 files changed

+175
-4
lines changed

src/safeposix/syscalls/fs_calls.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,8 +1099,8 @@ impl Cage {
10991099
/// O_WRONLY flags.
11001100
/// There are generally two cases which occur when this syscall happens:
11011101
/// Case 1: If the file to be opened doesn't exist, then due to O_CREAT flag,
1102-
/// a new file is created at the given location and a new file descriptor is
1103-
/// created and returned.
1102+
/// a new file is created at the given location and a new file descriptor is
1103+
/// created and returned.
11041104
/// Case 2: If the file already exists, then due to O_TRUNC flag, the file
11051105
/// size gets reduced to 0, and the existing file descriptor is returned.
11061106
///
@@ -3921,16 +3921,56 @@ impl Cage {
39213921
}
39223922

39233923
//------------------GETDENTS SYSCALL------------------
3924+
/// ## `getdents_syscall`
3925+
///
3926+
/// ### Description
3927+
/// This function reads directory entries from a directory file descriptor
3928+
/// and returns them in a buffer. Reading directory entries using multiple read calls can be less efficient because it
3929+
/// involves reading the data in smaller chunks and then parsing it.
3930+
/// getdents can often be faster by reading directory entries in a more optimized way.
3931+
/// * The function first checks if the provided buffer size is sufficient to store at least one
3932+
/// `ClippedDirent` structure.
3933+
/// * The function validates the provided file descriptor to ensure it represents a
3934+
/// valid file.
3935+
/// * The function checks if the file descriptor refers to a directory.
3936+
/// * The function iterates over the directory entries in the
3937+
/// `filename_to_inode_dict` of the directory inode.
3938+
/// * For each entry, the function constructs a `ClippedDirent` structure, which
3939+
/// contains the inode number, offset, and record length.
3940+
/// * It packs the constructed directory entries into the provided buffer (`dirp`).
3941+
/// * Updates the file position to the next directory entry to be read.
3942+
///
3943+
/// ### Function Arguments
3944+
/// * `fd`: A file descriptor representing the directory to read.
3945+
/// * `dirp`: A pointer to a buffer where the directory entries will be written.
3946+
/// * `bufsize`: The size of the buffer in bytes.
3947+
///
3948+
/// ### Returns
3949+
/// * The number of bytes written to the buffer on success.
3950+
///
3951+
/// ### Errors
3952+
/// * `EINVAL(22)`: If the buffer size is too small or if the file descriptor is invalid.
3953+
/// * `ENOTDIR(20)`: If the file descriptor does not refer to a existing directory.
3954+
/// * `ESPIPE(29)`: If the file descriptor does not refer to a file.
3955+
/// * `EBADF(9)` : If the file descriptor is invalid.
3956+
/// ### Panics
3957+
/// * There are no panics in this syscall.
39243958
39253959
pub fn getdents_syscall(&self, fd: i32, dirp: *mut u8, bufsize: u32) -> i32 {
39263960
let mut vec: Vec<(interface::ClippedDirent, Vec<u8>)> = Vec::new();
39273961

39283962
// make sure bufsize is at least greater than size of a ClippedDirent struct
3963+
// ClippedDirent is a simplified version of the traditional dirent structure used in POSIX systems
3964+
// By using a simpler structure, SafePosix can store and retrieve directory entries more efficiently,
3965+
// potentially improving performance compared to using the full dirent structure.
39293966
if bufsize <= interface::CLIPPED_DIRENT_SIZE {
39303967
return syscall_error(Errno::EINVAL, "getdents", "Result buffer is too small.");
39313968
}
39323969

3933-
let checkedfd = self.get_filedescriptor(fd).unwrap();
3970+
let checkedfd = match self.get_filedescriptor(fd) {
3971+
Ok(fd) => fd,
3972+
Err(_) => return syscall_error(Errno::EBADF, "getdents", "Invalid file descriptor."),
3973+
};
39343974
let mut unlocked_fd = checkedfd.write();
39353975
if let Some(filedesc_enum) = &mut *unlocked_fd {
39363976
match filedesc_enum {
@@ -3960,7 +4000,7 @@ impl Cage {
39604000
// convert filename to a filename vector of u8
39614001
let mut vec_filename: Vec<u8> = filename.as_bytes().to_vec();
39624002
vec_filename.push(b'\0'); // make filename null-terminated
3963-
4003+
// Push DT_UNKNOWN as d_type. This is a placeholder for now, as the actual file type is not yet determined.
39644004
vec_filename.push(DT_UNKNOWN); // push DT_UNKNOWN as d_type (for now)
39654005
temp_len =
39664006
interface::CLIPPED_DIRENT_SIZE + vec_filename.len() as u32; // get length of current filename vector for padding calculation
@@ -3996,6 +4036,8 @@ impl Cage {
39964036
count += 1;
39974037
}
39984038
// update file position
4039+
// keeps track of the current position within the directory. It indicates which directory entry the
4040+
// function should read next.
39994041
normalfile_filedesc_obj.position = interface::rust_min(
40004042
position + count,
40014043
dir_inode_obj.filename_to_inode_dict.len(),

src/tests/fs_tests.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,135 @@ pub mod fs_tests {
17821782
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
17831783
lindrustfinalize();
17841784
}
1785+
#[test]
1786+
fn ut_lind_fs_getdents_invalid_fd() {
1787+
let _thelock = setup::lock_and_init();
1788+
let cage = interface::cagetable_getref(1);
1789+
1790+
let bufsize = 50;
1791+
let mut vec = vec![0u8; bufsize as usize];
1792+
let baseptr: *mut u8 = &mut vec[0];
1793+
1794+
// Create a directory
1795+
assert_eq!(cage.mkdir_syscall("/getdents", S_IRWXA), 0);
1796+
1797+
// Open the directory
1798+
let fd = cage.open_syscall("/getdents", O_RDWR, S_IRWXA);
1799+
1800+
// Attempt to call `getdents_syscall` with an invalid file descriptor
1801+
let result = cage.getdents_syscall(-1, baseptr, bufsize as u32);
1802+
1803+
// Assert that the return value is EBADF (errno for "Bad file descriptor")
1804+
assert_eq!(result, -(Errno::EBADF as i32));
1805+
1806+
// Close the directory
1807+
assert_eq!(cage.close_syscall(fd), 0);
1808+
1809+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1810+
lindrustfinalize();
1811+
}
1812+
1813+
#[test]
1814+
fn ut_lind_fs_getdents_out_of_range_fd() {
1815+
// Acquire a lock on TESTMUTEX to prevent other tests from running concurrently,
1816+
// and also perform clean environment setup.
1817+
let _thelock = setup::lock_and_init();
1818+
1819+
let cage = interface::cagetable_getref(1);
1820+
1821+
// Allocate a buffer to store directory entries
1822+
let bufsize = 1024;
1823+
let mut vec = vec![0u8; bufsize as usize];
1824+
let baseptr: *mut u8 = &mut vec[0];
1825+
1826+
// Attempt to call getdents_syscall with a file descriptor out of range
1827+
let result = cage.getdents_syscall(MAXFD + 1, baseptr, bufsize as u32);
1828+
1829+
// Verify that it returns EBADF (errno for "Bad file descriptor")
1830+
assert_eq!(result, -(Errno::EBADF as i32));
1831+
1832+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1833+
lindrustfinalize();
1834+
}
1835+
1836+
#[test]
1837+
fn ut_lind_fs_getdents_non_existing_fd() {
1838+
// Acquire a lock on TESTMUTEX to prevent other tests from running concurrently,
1839+
// and also perform clean environment setup.
1840+
let _thelock = setup::lock_and_init();
1841+
1842+
let cage = interface::cagetable_getref(1);
1843+
1844+
// Allocate a buffer to store directory entries
1845+
let bufsize = 1024;
1846+
let mut vec = vec![0u8; bufsize as usize];
1847+
let baseptr: *mut u8 = &mut vec[0];
1848+
1849+
// Attempt to call getdents_syscall with a non-existing file descriptor
1850+
let result = cage.getdents_syscall(100, baseptr, bufsize as u32);
1851+
1852+
// Verify that it returns EBADF (errno for "Bad file descriptor")
1853+
assert_eq!(result, -(Errno::EBADF as i32));
1854+
1855+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1856+
lindrustfinalize();
1857+
}
1858+
1859+
#[test]
1860+
fn ut_lind_fs_getdents_bufsize_too_small() {
1861+
let _thelock = setup::lock_and_init();
1862+
let cage = interface::cagetable_getref(1);
1863+
1864+
let bufsize = interface::CLIPPED_DIRENT_SIZE - 1; // Buffer size smaller than CLIPPED_DIRENT_SIZE
1865+
let mut vec = vec![0u8; bufsize as usize];
1866+
let baseptr: *mut u8 = &mut vec[0];
1867+
1868+
// Create a directory
1869+
assert_eq!(cage.mkdir_syscall("/getdents", S_IRWXA), 0);
1870+
1871+
// Open the directory
1872+
let fd = cage.open_syscall("/getdents", O_RDWR, S_IRWXA);
1873+
1874+
// Attempt to call `getdents_syscall` with a buffer size smaller than CLIPPED_DIRENT_SIZE
1875+
let result = cage.getdents_syscall(fd, baseptr, bufsize as u32);
1876+
1877+
// Assert that the return value is EINVAL (errno for "Invalid argument")
1878+
assert_eq!(result, -(Errno::EINVAL as i32));
1879+
1880+
// Close the directory
1881+
assert_eq!(cage.close_syscall(fd), 0);
1882+
1883+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1884+
lindrustfinalize();
1885+
}
1886+
1887+
#[test]
1888+
fn ut_lind_fs_getdents_non_directory_fd() {
1889+
// Acquire a lock on TESTMUTEX to prevent other tests from running concurrently,
1890+
// and also perform clean environment setup.
1891+
let _thelock = setup::lock_and_init();
1892+
1893+
let cage = interface::cagetable_getref(1);
1894+
1895+
// Create a regular file
1896+
let filepath = "/regularfile";
1897+
let fd = cage.open_syscall(filepath, O_CREAT | O_WRONLY, S_IRWXA);
1898+
assert!(fd >= 0);
1899+
// Allocate a buffer to store directory entries
1900+
let bufsize = 1024;
1901+
let mut vec = vec![0u8; bufsize as usize];
1902+
let baseptr: *mut u8 = &mut vec[0];
1903+
1904+
// Attempt to call getdents_syscall on the regular file descriptor
1905+
let result = cage.getdents_syscall(fd, baseptr, bufsize as u32);
1906+
// Verify that it returns ENOTDIR
1907+
assert_eq!(result, -(Errno::ENOTDIR as i32));
1908+
1909+
// Clean up: Close the file descriptor and finalize the test environment
1910+
assert_eq!(cage.close_syscall(fd), 0);
1911+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1912+
lindrustfinalize();
1913+
}
17851914

17861915
#[test]
17871916
pub fn ut_lind_fs_dir_chdir_getcwd() {

0 commit comments

Comments
 (0)