Skip to content

Commit 69a31d5

Browse files
Added tests for mkdir_syscall (#255)
* Added tests for mkdir_syscall * Added symlink test for mkdir_syscall * Updated symlink test for mkdir_syscall * Updated fs_mkdir call with comments and updated test * Added information as comments
1 parent 20a5d75 commit 69a31d5

File tree

2 files changed

+148
-18
lines changed

2 files changed

+148
-18
lines changed

src/safeposix/syscalls/fs_calls.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -181,72 +181,102 @@ impl Cage {
181181
}
182182

183183
//------------------MKDIR SYSCALL------------------
184-
184+
// Description
185+
// The mkdir_syscall() creates a new directory named by the path name pointed to by a path as the input parameter in the function.
186+
// The mode of the new directory is initialized from the "mode" provided as the input parameter in the function.
187+
// The newly created directory is empty with size 0 and is associated with a new inode of type "DIR".
188+
// On successful completion, the timestamps for both the newly formed directory and its parent are updated along with their linkcounts.
189+
190+
// Function Arguments
191+
// The mkdir_syscall() receives two arguments:
192+
// 1. Path - This represents the path at which the new directory will be created.
193+
// For example: "/parentdir/dir" represents the new directory name as "dir", which will be created at this path (/parentdir/dir).
194+
// 2. Mode - This represents the permission of the newly created directory.
195+
// The general mode used is "S_IRWXA": which represents the read, write, and search permissions on the new directory.
196+
197+
// Return Values
198+
// Upon successful creation of the directory, 0 is returned.
199+
// Otherwise, an error with a proper errorNumber and errorMessage is returned based on the different scenarios.
200+
//
201+
// Tests
202+
// All the different scenarios for mkdir_syscall() are covered and tested in the "fs_tests.rs" file under "mkdir_syscall_tests" section.
203+
//
185204
pub fn mkdir_syscall(&self, path: &str, mode: u32) -> i32 {
186-
//Check that path is not empty
205+
206+
// Check that the given input path is not empty
187207
if path.len() == 0 {
188208
return syscall_error(Errno::ENOENT, "mkdir", "given path was null");
189209
}
190-
let truepath = normpath(convpath(path), self);
191210

192-
//pass the metadata to this helper. If passed table is none, then create new instance
211+
// Store the FileMetadata into a helper variable which is used for fetching the metadata of a given inode from the Inode Table.
193212
let metadata = &FS_METADATA;
194213

214+
// Retrieve the absolute path from the root directory. The absolute path is then used to validate directory paths
215+
// while navigating through subdirectories and establishing new directory at the given location.
216+
let truepath = normpath(convpath(path), self);
217+
218+
// Walk through the absolute path which returns a tuple consisting of inode number of file (if it exists), and inode number of parent (if it exists)
195219
match metawalkandparent(truepath.as_path()) {
196-
//If neither the file nor parent exists
220+
// Case 1: When neither the file directory nor the parent directory exists
197221
(None, None) => syscall_error(
198222
Errno::ENOENT,
199223
"mkdir",
200224
"a directory component in pathname does not exist or is a dangling symbolic link",
201225
),
202226

203-
//If the file doesn't exist but the parent does
227+
// Case 2: When the file doesn't exist but the parent directory exists
204228
(None, Some(pardirinode)) => {
205229
let filename = truepath.file_name().unwrap().to_str().unwrap().to_string(); //for now we assume this is sane, but maybe this should be checked later
206230

207231
let effective_mode = S_IFDIR as u32 | mode;
208-
209-
//assert sane mode bits
232+
// Check for the condition if the mode bits are correct and have the required permissions to create a directory
210233
if mode & (S_IRWXA | S_FILETYPEFLAGS as u32) != mode {
211234
return syscall_error(Errno::EPERM, "mkdir", "Mode bits were not sane");
212235
}
213236

237+
// Fetch the next available inode number using the FileSystem MetaData table
238+
// Create a new inode of type "Dir" representing a directory and set the required attributes
214239
let newinodenum = FS_METADATA
215240
.nextinode
216241
.fetch_add(1, interface::RustAtomicOrdering::Relaxed); //fetch_add returns the previous value, which is the inode number we want
217242
let time = interface::timestamp(); //We do a real timestamp now
218-
219243
let newinode = Inode::Dir(DirectoryInode {
220-
size: 0,
244+
size: 0, //initial size of a directory is 0 as it is empty
221245
uid: DEFAULT_UID,
222246
gid: DEFAULT_GID,
223247
mode: effective_mode,
224-
linkcount: 3,
225-
refcount: 0, //2 because ., and .., as well as reference in parent directory
248+
linkcount: 3, //because of the directory name(.), itself, and reference to the parent directory(..)
249+
refcount: 0, //because no file descriptors are pointing to it currently
226250
atime: time,
227251
ctime: time,
228252
mtime: time,
229-
filename_to_inode_dict: init_filename_to_inode_dict(newinodenum, pardirinode),
253+
filename_to_inode_dict: init_filename_to_inode_dict(newinodenum, pardirinode), //Establish a mapping between the newly created inode and the parent directory inode for easy retrieval and linking
230254
});
231255

232-
if let Inode::Dir(ref mut parentdir) =
233-
*(metadata.inodetable.get_mut(&pardirinode).unwrap())
256+
// Insert a reference to the file in the parent directory and update the inode attributes
257+
// Fetch the inode of the parent directory and only proceed when its type is directory.
258+
if let Inode::Dir(ref mut parentdir) = *(metadata.inodetable.get_mut(&pardirinode).unwrap())
234259
{
235260
parentdir
236261
.filename_to_inode_dict
237262
.insert(filename, newinodenum);
238-
parentdir.linkcount += 1;
263+
parentdir.linkcount += 1; // Since the parent is now associated to the new directory, its linkcount will increment by 1
264+
parentdir.ctime = time; // Here, update the ctime and mtime for the parent directory as well
265+
parentdir.mtime = time;
239266
}
240-
//insert a reference to the file in the parent directory
241267
else {
242268
unreachable!();
243269
}
270+
// Update the inode table by inserting the newly formed inode mapped with its inode number.
244271
metadata.inodetable.insert(newinodenum, newinode);
245272
log_metadata(&metadata, pardirinode);
246273
log_metadata(&metadata, newinodenum);
247-
0 //mkdir has succeeded
274+
275+
// Return 0 when mkdir has succeeded
276+
0
248277
}
249278

279+
// Case 3: When the file directory name already exists, then return the error.
250280
(Some(_), ..) => syscall_error(
251281
Errno::EEXIST,
252282
"mkdir",

src/tests/fs_tests.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ pub mod fs_tests {
5050
ut_lind_fs_sem_trytimed();
5151
ut_lind_fs_sem_test();
5252
ut_lind_fs_tmp_file_test();
53+
54+
//mkdir_syscall_tests
55+
ut_lind_fs_mkdir_empty_directory();
56+
ut_lind_fs_mkdir_nonexisting_directory();
57+
ut_lind_fs_mkdir_existing_directory();
58+
ut_lind_fs_mkdir_invalid_modebits();
59+
ut_lind_fs_mkdir_success();
60+
ut_lind_fs_mkdir_using_symlink();
5361
}
5462

5563
pub fn ut_lind_fs_simple() {
@@ -1237,6 +1245,98 @@ pub mod fs_tests {
12371245
// Check if file is still there (it shouldn't be, assert no)
12381246
assert_eq!(cage.access_syscall(file_path, F_OK), -2);
12391247

1248+
lindrustfinalize();
1249+
}
1250+
1251+
pub fn ut_lind_fs_mkdir_empty_directory() {
1252+
lindrustinit(0);
1253+
let cage = interface::cagetable_getref(1);
1254+
let path = "";
1255+
// Check for error when directory is empty
1256+
assert_eq!(cage.mkdir_syscall(path, S_IRWXA), -(Errno::ENOENT as i32));
1257+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1258+
lindrustfinalize();
1259+
}
1260+
1261+
pub fn ut_lind_fs_mkdir_nonexisting_directory() {
1262+
lindrustinit(0);
1263+
let cage = interface::cagetable_getref(1);
1264+
let path = "/parentdir/dir";
1265+
// Check for error when both parent and child directories don't exist
1266+
assert_eq!(cage.mkdir_syscall(path, S_IRWXA), -(Errno::ENOENT as i32));
1267+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1268+
lindrustfinalize();
1269+
}
1270+
1271+
pub fn ut_lind_fs_mkdir_existing_directory() {
1272+
lindrustinit(0);
1273+
let cage = interface::cagetable_getref(1);
1274+
let path = "/parentdir";
1275+
// Create a parent directory
1276+
cage.mkdir_syscall(path, S_IRWXA);
1277+
// Check for error when the same directory is created again
1278+
assert_eq!(cage.mkdir_syscall(path, S_IRWXA), -(Errno::EEXIST as i32));
1279+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1280+
lindrustfinalize();
1281+
}
1282+
1283+
pub fn ut_lind_fs_mkdir_invalid_modebits() {
1284+
lindrustinit(0);
1285+
let cage = interface::cagetable_getref(1);
1286+
let path = "/parentdir";
1287+
let invalid_mode = 0o77777; // Invalid mode bits
1288+
// Create a parent directory
1289+
cage.mkdir_syscall(path, S_IRWXA);
1290+
// Check for error when a directory is being created with invalid mode
1291+
assert_eq!(cage.mkdir_syscall("/parentdir/dir", invalid_mode), -(Errno::EPERM as i32));
1292+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1293+
lindrustfinalize();
1294+
}
1295+
1296+
pub fn ut_lind_fs_mkdir_success() {
1297+
lindrustinit(0);
1298+
let cage = interface::cagetable_getref(1);
1299+
let path = "/parentdir";
1300+
// Create a parent directory
1301+
cage.mkdir_syscall(path, S_IRWXA);
1302+
1303+
// Get the stat data for the parent directory and check for inode link count to be 3 initially
1304+
let mut statdata = StatData::default();
1305+
assert_eq!(cage.stat_syscall(path, &mut statdata), 0);
1306+
assert_eq!(statdata.st_nlink, 3);
1307+
1308+
// Create a child directory inside parent directory with valid mode bits
1309+
assert_eq!(cage.mkdir_syscall("/parentdir/dir", S_IRWXA), 0);
1310+
1311+
// Get the stat data for the child directory and check for inode link count to be 3 initially
1312+
let mut statdata2 = StatData::default();
1313+
assert_eq!(cage.stat_syscall("/parentdir/dir", &mut statdata2), 0);
1314+
assert_eq!(statdata2.st_nlink, 3);
1315+
1316+
// Get the stat data for the parent directory and check for inode link count to be 4 now as a new child directory has been created.
1317+
let mut statdata3 = StatData::default();
1318+
assert_eq!(cage.stat_syscall(path, &mut statdata3), 0);
1319+
assert_eq!(statdata3.st_nlink, 4);
1320+
1321+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
1322+
lindrustfinalize();
1323+
}
1324+
1325+
pub fn ut_lind_fs_mkdir_using_symlink() {
1326+
lindrustinit(0);
1327+
let cage = interface::cagetable_getref(1);
1328+
1329+
// Create a file which will be referred to as originalFile
1330+
let fd = cage.open_syscall("/originalFile", O_CREAT | O_EXCL | O_WRONLY, S_IRWXA);
1331+
assert_eq!(cage.write_syscall(fd, str2cbuf("hi"), 2), 2);
1332+
1333+
// Create a link between two files where the symlinkFile is originally not present
1334+
// But while linking, symlinkFile will get created
1335+
assert_eq!(cage.link_syscall("/originalFile", "/symlinkFile"), 0);
1336+
1337+
// Check for error while creating the symlinkFile again as it would already be created while linking the two files above.
1338+
assert_eq!(cage.mkdir_syscall("/symlinkFile", S_IRWXA), -(Errno::EEXIST as i32));
1339+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
12401340
lindrustfinalize();
12411341
}
12421342
}

0 commit comments

Comments
 (0)