Skip to content

Commit 9385a31

Browse files
pranav-bhattpranav
andauthored
Description, Comments and tests for stat_syscall & fstat_syscall (#301)
* added comments for stat_syscall Signed-off-by: pranav <pranav.b@cloudera.com> * added the first few test cases * fstat_syscall documentation * completed test suite for stat_sycall * removed unnecessary import * FMT#1 * added fstat description + comments + tests * added incorporated comment feedback * reviewed documentation * corrected panic description in stat * fixed fstat panic bug * fixed fstat panic bug + modified test case to account for this * updated test case * addressed comments * addressed more comments * addressed more comments #2 * removed panic catch+unwind * removed extra import --------- Signed-off-by: pranav <pranav.b@cloudera.com> Co-authored-by: pranav <pranav.b@cloudera.com>
1 parent 18b7895 commit 9385a31

File tree

6 files changed

+292
-49
lines changed

6 files changed

+292
-49
lines changed

src/safeposix/filesystem.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ pub enum Inode {
5050
}
5151

5252
#[derive(interface::SerdeSerialize, interface::SerdeDeserialize, Debug)]
53+
/// Refer [here](https://man7.org/linux/man-pages/man7/inode.7.html)
54+
/// for more information on the below fields.
5355
pub struct GenericInode {
5456
pub size: usize,
5557
pub uid: u32,
@@ -66,6 +68,8 @@ pub struct GenericInode {
6668
}
6769

6870
#[derive(interface::SerdeSerialize, interface::SerdeDeserialize, Debug)]
71+
/// Refer [here](https://man7.org/linux/man-pages/man7/inode.7.html)
72+
/// for more information on the below fields.
6973
pub struct DeviceInode {
7074
pub size: usize,
7175
pub uid: u32,
@@ -83,6 +87,8 @@ pub struct DeviceInode {
8387
}
8488

8589
#[derive(interface::SerdeSerialize, interface::SerdeDeserialize, Debug)]
90+
/// Refer [here](https://man7.org/linux/man-pages/man7/inode.7.html)
91+
/// for more information on the below fields.
8692
pub struct SocketInode {
8793
pub size: usize,
8894
pub uid: u32,
@@ -97,6 +103,8 @@ pub struct SocketInode {
97103
}
98104

99105
#[derive(interface::SerdeSerialize, interface::SerdeDeserialize, Debug)]
106+
/// Refer [here](https://man7.org/linux/man-pages/man7/inode.7.html)
107+
/// for more information on the below fields.
100108
pub struct DirectoryInode {
101109
pub size: usize,
102110
pub uid: u32,

src/safeposix/syscalls/fs_calls.rs

Lines changed: 124 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,12 +1148,47 @@ impl Cage {
11481148
}
11491149

11501150
//------------------------------------STAT SYSCALL------------------------------------
1151+
/// ### Description
1152+
///
1153+
/// `stat_syscall` retrieves file information for the file specified by
1154+
/// `path` and populates the provided `statbuf` with this information.
1155+
/// Although no file permissions are required to perform the call, execute
1156+
/// (search) permission is required on all of the directories in
1157+
/// pathname that lead to the file.
1158+
///
1159+
/// ### Arguments
1160+
///
1161+
/// It accepts two parameters:
1162+
/// * `path` - A string slice that specifies the file path for which status
1163+
/// information is to be retrieved.
1164+
/// * `statbuf` - A mutable reference to a `StatData` struct where the file
1165+
/// status will be stored.
1166+
///
1167+
/// ### Returns
1168+
///
1169+
/// For a successful call, the return value will be 0. On error, a negative
1170+
/// errno is returned to indicate the error.
1171+
///
1172+
/// ### Errors
1173+
///
1174+
/// * `ENOENT` - The file specified by `path` does not exist or the path is
1175+
/// invalid.
1176+
///
1177+
/// ### Panics
1178+
///
1179+
/// * This function does not have any known panics.
1180+
///
1181+
/// For more detailed description of all the commands and return values,
1182+
/// refer to the stat man page [here](https://man7.org/linux/man-pages/man2/stat.2.html).
11511183
11521184
pub fn stat_syscall(&self, path: &str, statbuf: &mut StatData) -> i32 {
1185+
//convert the path to an absolute path of type `PathBuf`
11531186
let truepath = normpath(convpath(path), self);
11541187

11551188
//Walk the file tree to get inode from path
11561189
if let Some(inodenum) = metawalk(truepath.as_path()) {
1190+
// won't panic since check for inode number in table is already happening in
1191+
// above 'metawalk' function
11571192
let inodeobj = FS_METADATA.inodetable.get(&inodenum).unwrap();
11581193

11591194
//populate those fields in statbuf which depend on things other than the inode
@@ -1182,6 +1217,9 @@ impl Cage {
11821217
}
11831218
}
11841219

1220+
// helper function to populate information of generic inode objects (for example
1221+
// a file) into the statbuf. Refer [here](https://man7.org/linux/man-pages/man7/inode.7.html)
1222+
// for more information on the fields being populated below.
11851223
fn _istat_helper(inodeobj: &GenericInode, statbuf: &mut StatData) {
11861224
statbuf.st_mode = inodeobj.mode;
11871225
statbuf.st_nlink = inodeobj.linkcount;
@@ -1193,6 +1231,9 @@ impl Cage {
11931231
statbuf.st_blocks = 0;
11941232
}
11951233

1234+
// helper function to populate information of socket inode object into the
1235+
// statbuf. Refer [here](https://man7.org/linux/man-pages/man7/inode.7.html)
1236+
// for more information on the fields being populated below.
11961237
fn _istat_helper_sock(inodeobj: &SocketInode, statbuf: &mut StatData) {
11971238
statbuf.st_mode = inodeobj.mode;
11981239
statbuf.st_nlink = inodeobj.linkcount;
@@ -1204,6 +1245,9 @@ impl Cage {
12041245
statbuf.st_blocks = 0;
12051246
}
12061247

1248+
// helper function to populate information of directory inode object into the
1249+
// statbuf. Refer [here](https://man7.org/linux/man-pages/man7/inode.7.html)
1250+
// for more information on the fields being populated below.
12071251
fn _istat_helper_dir(inodeobj: &DirectoryInode, statbuf: &mut StatData) {
12081252
statbuf.st_mode = inodeobj.mode;
12091253
statbuf.st_nlink = inodeobj.linkcount;
@@ -1215,6 +1259,9 @@ impl Cage {
12151259
statbuf.st_blocks = 0;
12161260
}
12171261

1262+
// helper function to populate information of device inode object into the
1263+
// statbuf. Refer [here](https://man7.org/linux/man-pages/man7/inode.7.html)
1264+
// for more information on the fields being populated below.
12181265
fn _istat_helper_chr_file(inodeobj: &DeviceInode, statbuf: &mut StatData) {
12191266
statbuf.st_dev = 5;
12201267
statbuf.st_mode = inodeobj.mode;
@@ -1226,7 +1273,7 @@ impl Cage {
12261273
statbuf.st_size = inodeobj.size;
12271274
}
12281275

1229-
//Streams and pipes don't have associated inodes so we populate them from
1276+
// Streams and pipes don't have associated inodes so we populate them from
12301277
// mostly dummy information
12311278
fn _stat_alt_helper(&self, statbuf: &mut StatData, inodenum: usize) {
12321279
statbuf.st_dev = FS_METADATA.dev_id;
@@ -1242,18 +1289,67 @@ impl Cage {
12421289
}
12431290

12441291
//------------------------------------FSTAT SYSCALL------------------------------------
1292+
/// ### Description
1293+
///
1294+
/// `fstat_syscall` retrieves file status information for the file specified
1295+
/// by the file descriptor `fd` and populates the provided `statbuf`
1296+
/// with this information.
1297+
///
1298+
/// ### Arguments
1299+
///
1300+
/// It accepts two parameters:
1301+
/// * `fd` - The file descriptor for the file for which we need the status
1302+
/// information.
1303+
/// * `statbuf` - A mutable reference to a `StatData` struct where the file
1304+
/// status will be stored.
1305+
///
1306+
/// ### Returns
1307+
///
1308+
/// For a successful call, the return value will be 0. On error, a negative
1309+
/// errno is returned to indicate the error.
1310+
///
1311+
/// ### Errors
1312+
///
1313+
/// * `EBADF` - The file descriptor `fd` is invalid.
1314+
/// * `EOPNOTSUPP` - `fstat` is not supported on sockets.
1315+
///
1316+
/// ### Panics
1317+
///
1318+
/// * If the file descriptor passed is invalid (less than zero or greater
1319+
/// than MAX FD which is 1024)
1320+
/// * If the inode number retrieved from the file descriptor does not exist
1321+
/// in `FS_METADATA.inodetable`.
1322+
///
1323+
/// For more detailed description of all the commands and return values,
1324+
/// refer to the stat man page [here](https://man7.org/linux/man-pages/man2/stat.2.html).
12451325
12461326
pub fn fstat_syscall(&self, fd: i32, statbuf: &mut StatData) -> i32 {
1327+
// Attempt to get the file descriptor
1328+
// BUG: This can panic if there is an invalid file descriptor provided
12471329
let checkedfd = self.get_filedescriptor(fd).unwrap();
1330+
1331+
// Acquire a write lock on the file descriptor to ensure exclusive access.
12481332
let unlocked_fd = checkedfd.read();
1333+
12491334
if let Some(filedesc_enum) = &*unlocked_fd {
1250-
//Delegate populating statbuf to the relevant helper depending on the file
1335+
// Delegate populating statbuf to the relevant helper depending on the file
12511336
// type. First we check in the file descriptor to handle sockets,
12521337
// streams, and pipes, and if it is a normal file descriptor we
12531338
// handle regular files, dirs, and char files based on the
12541339
// information in the inode.
12551340
match filedesc_enum {
1341+
// Fail faster for sockets
1342+
Socket(_) => {
1343+
return syscall_error(
1344+
Errno::EOPNOTSUPP,
1345+
"fstat",
1346+
"we don't support fstat on sockets yet",
1347+
);
1348+
}
1349+
1350+
// if a normal file descriptor is found
12561351
File(normalfile_filedesc_obj) => {
1352+
// fetch the inode object of the normal file
12571353
let inode = FS_METADATA
12581354
.inodetable
12591355
.get(&normalfile_filedesc_obj.inode)
@@ -1264,6 +1360,7 @@ impl Cage {
12641360
statbuf.st_ino = normalfile_filedesc_obj.inode;
12651361
statbuf.st_dev = FS_METADATA.dev_id;
12661362

1363+
// match inode to one of 4 inode types
12671364
match &*inode {
12681365
Inode::File(f) => {
12691366
Self::_istat_helper(&f, statbuf);
@@ -1279,21 +1376,17 @@ impl Cage {
12791376
}
12801377
}
12811378
}
1282-
Socket(_) => {
1283-
return syscall_error(
1284-
Errno::EOPNOTSUPP,
1285-
"fstat",
1286-
"we don't support fstat on sockets yet",
1287-
);
1288-
}
1379+
// Streams don't have inodes, so we'll populate statbuf with dummy info
12891380
Stream(_) => {
12901381
self._stat_alt_helper(statbuf, STREAMINODE);
12911382
}
1383+
// Pipes don't have inodes, so we'll populate statbuf with dummy info
12921384
Pipe(_) => {
1293-
self._stat_alt_helper(statbuf, 0xfeef0000);
1385+
self._stat_alt_helper(statbuf, PIPEINODE);
12941386
}
1387+
// Epolls don't have inodes, so we'll populate statbuf with dummy info
12951388
Epoll(_) => {
1296-
self._stat_alt_helper(statbuf, 0xfeef0000);
1389+
self._stat_alt_helper(statbuf, EPOLLINODE);
12971390
}
12981391
}
12991392
0 //fstat has succeeded!
@@ -5212,40 +5305,40 @@ impl Cage {
52125305
}
52135306

52145307
/// ### Description
5215-
///
5308+
///
52165309
/// `shmget_syscall` returns the shared memory segment identifier associated with a particular `key`
52175310
/// If a key doesn't exist, shmget creates a new memory segment and attaches it to the key.
5218-
/// Traditionally if the value of the key equals `IPC_PRIVATE`, we also create a new memory segment which
5219-
/// is not associated with a key during this syscall,
5220-
/// but for our implementaion, we return an error and only create a new memory
5311+
/// Traditionally if the value of the key equals `IPC_PRIVATE`, we also create a new memory segment which
5312+
/// is not associated with a key during this syscall,
5313+
/// but for our implementaion, we return an error and only create a new memory
52215314
/// segment when the IPC_CREAT flag is specified in the`shmflag` argument.
5222-
///
5223-
/// ### Returns
5224-
///
5315+
///
5316+
/// ### Returns
5317+
///
52255318
/// An 32 bit integer which represens the identifier of the memory segment associated with the key
5226-
///
5319+
///
52275320
/// ### Arguments
5228-
///
5321+
///
52295322
/// `key` : An i32 value that references a memory segment
52305323
/// `size` : Size of the memory segment to be created if key doesn't exist
52315324
/// `shmflag` : mode flags which indicate whether to create a new key or not
5232-
/// The `shmflag` is composed of the following
5325+
/// The `shmflag` is composed of the following
52335326
/// * IPC_CREAT - specify that the system call creates a new segment
5234-
/// * IPC_EXCL - this flag is used with IPC_CREAT to cause this function to fail when IPC_CREAT is also used
5327+
/// * IPC_EXCL - this flag is used with IPC_CREAT to cause this function to fail when IPC_CREAT is also used
52355328
/// and the key passed has a memory segment associated with it.
5236-
///
5237-
/// ### Errors
5238-
///
5329+
///
5330+
/// ### Errors
5331+
///
52395332
/// * ENOENT : the key equals the `IPC_PRIVATE` constant
52405333
/// * EEXIST : key exists and yet either `IPC_CREAT` or `IPC_EXCL` are passed as flags
52415334
/// * ENOENT : key did not exist and the `IPC_CREAT` flag was not passed
52425335
/// * EINVAL : the size passed was less than the minimum size of segment or greater than the maximum possible size
5243-
///
5336+
///
52445337
/// ### Panics
5245-
///
5338+
///
52465339
/// There are no cases where the function directly panics
5247-
///
5248-
pub fn shmget_syscall(&self, key: i32, size: usize, shmflg: i32) -> i32 {
5340+
///
5341+
pub fn shmget_syscall(&self, key: i32, size: usize, shmflg: i32) -> i32 {
52495342
//Check if the key passed equals the IPC_PRIVATE flag
52505343
if key == IPC_PRIVATE {
52515344
// Return error since this is not suppported currently
@@ -5297,7 +5390,7 @@ impl Cage {
52975390
// Insert new id in the hash table entry pointed by the key
52985391
vacant.insert(shmid);
52995392
// Mode of the new segment is the 9 least significant bits of the shmflag
5300-
let mode = (shmflg & 0x1FF) as u16;
5393+
let mode = (shmflg & 0x1FF) as u16;
53015394
// Create a new segment with the key, size, cageid of the calling process
53025395
let segment = new_shm_segment(
53035396
key,
@@ -5312,7 +5405,7 @@ impl Cage {
53125405
}
53135406
};
53145407
// Return the shmid
5315-
shmid
5408+
shmid
53165409
}
53175410

53185411
//------------------SHMAT SYSCALL------------------

src/safeposix/syscalls/fs_constants.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ pub const STARTINGPIPE: i32 = 0;
1414
pub const MAXPIPE: i32 = 1024;
1515

1616
pub const ROOTDIRECTORYINODE: usize = 1;
17-
pub const STREAMINODE: usize = 2;
17+
pub const STREAMINODE: usize = 2; // Dummy value
18+
pub const PIPEINODE: usize = 0xfeef0000; // Dummy value
19+
pub const EPOLLINODE: usize = 0xfeef0000; // Dummy value
1820

1921
pub const PIPE_CAPACITY: usize = 65536;
2022

src/safeposix/syscalls/sys_calls.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ impl Cage {
433433
/// ### Panics
434434
///
435435
/// This function doesn't directly panic - but the unmap memory mappings
436-
/// function panics if it cannot create an shm entry or if the unwrapping
436+
/// function panics if it cannot create an shm entry or if the unwrapping
437437
/// on the file descriptor fails due to an invalid fd
438438
///
439439
/// For more information please refer to - [https://man7.org/linux/man-pages/man3/exec.3.html]
@@ -479,7 +479,8 @@ impl Cage {
479479
// yet - And there is no threadId to store it at.
480480
// The child Cage object can then initialize and store the sigset appropriately
481481
// when it establishes its own main thread id.
482-
// A sigset is a data structure that keeps track of which signals are affected by the process
482+
// A sigset is a data structure that keeps track of which signals are affected
483+
// by the process
483484
let newsigset = interface::RustHashMap::new();
484485
if !interface::RUSTPOSIX_TESTSUITE.load(interface::RustAtomicOrdering::Relaxed) {
485486
// When rustposix runs independently (not as Lind paired with NaCL runtime) we

0 commit comments

Comments
 (0)