diff --git a/src/interface/file.rs b/src/interface/file.rs index d10f1345..c5a65d90 100644 --- a/src/interface/file.rs +++ b/src/interface/file.rs @@ -206,26 +206,18 @@ impl EmulatedFile { bufs: &[IoSlice<'_>], offset: usize, ) -> std::io::Result { - let mut total_bytes_written = 0; //to keep track of the total number of bytes written. - + let mut total_bytes_written = 0; // To keep track of the total number of bytes written. + if let Some(f) = &self.fobj { - // checks if the file object (fobj) exists. - let mut file = f.lock(); - // Seek to the specified offset from the beginning of the file - file.seek(SeekFrom::Start(offset as u64))?; - // moves the file pointer to the desired starting position (offset) from the - // beginning of the file. - - // Use write_vectored for efficient writing from multiple buffers - total_bytes_written = file.write_vectored(bufs)?; - //It performs a vectored write operation,which means it - // writes data to the file from multiple buffers + // Use write_vectored_at directly + total_bytes_written = f.lock().write_vectored_at(bufs, offset as u64)?; } - // Update recorded filesize if we've written past the previous filesize + + // Update the recorded file size if we've written past the previous file size if offset + total_bytes_written > self.filesize { self.filesize = offset + total_bytes_written; } - + Ok(total_bytes_written) } diff --git a/src/interface/misc.rs b/src/interface/misc.rs index 7590aaa3..30e88039 100644 --- a/src/interface/misc.rs +++ b/src/interface/misc.rs @@ -131,34 +131,17 @@ pub fn concat_iovec_to_slice(iovec: *const interface::IovecStruct, iovcnt: i32) } //This function logs data from a slice to the specified file descriptor. -// It handles logging to standard output (fd 1) and standard error (fd 2). -// For other file descriptors, it uses a low-level approach to write the data. +// It handles logging to standard output -pub fn log_from_slice(fd: i32, data: &[u8]) -> Result { - match from_utf8(data) { + +pub fn log_from_slice(_fd: i32, data: &[u8]) -> Result { + match std::str::from_utf8(data) { Ok(s) => { - match fd { - 1 => { - // File descriptor 1 is standard output - io::stdout() - .write_all(s.as_bytes()) - .map_err(|_| "Failed to write to stdout".to_string())?; - } - 2 => { - // File descriptor 2 is standard error - io::stderr() - .write_all(s.as_bytes()) - .map_err(|_| "Failed to write to stderr".to_string())?; - } - _ => { - // For other file descriptors, we need to use a low-level approach - let result = - unsafe { libc::write(fd, s.as_ptr() as *const libc::c_void, s.len()) }; - if result < 0 { - return Err("Failed to write to file descriptor".to_string()); - } - } - } + // Log everything to stdout, regardless of the file descriptor provided + io::stdout() + .write_all(s.as_bytes()) + .map_err(|_| "Failed to write to stdout".to_string())?; + Ok(data.len() as i32) } Err(_) => Err("Failed to convert data to string".to_string()), diff --git a/src/lib.rs b/src/lib.rs index 336aed32..6c4f6338 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![feature(vec_into_raw_parts)] #![feature(thread_local)] #![allow(unused_imports)] +#![feature(unix_file_vectored_at)] //! # RustPOSIX //! Welcome to the RustPOSIX microvisor. diff --git a/src/tests/fs_tests.rs b/src/tests/fs_tests.rs index 0073fcc3..f37538b0 100644 --- a/src/tests/fs_tests.rs +++ b/src/tests/fs_tests.rs @@ -4739,39 +4739,109 @@ pub mod fs_tests { #[test] fn ut_lind_fs_writev_pipe() { - //acquiring a lock on TESTMUTEX prevents other tests from running concurrently, + // Acquiring a lock on TESTMUTEX prevents other tests from running concurrently, // and also performs clean env setup let _thelock = setup::lock_and_init(); let cage = interface::cagetable_getref(1); - + // Create a pipe let mut pipe_fds = PipeArray::default(); assert_eq!(cage.pipe_syscall(&mut pipe_fds), 0); let read_fd = pipe_fds.readfd; let write_fd = pipe_fds.writefd; + + // Prepare multiple data segments to be written using an iovec structure + let data1 = b"Hello, "; + let data2 = b"pipe!"; + let data3 = b" Testing writev."; + + let iovec = [ + interface::IovecStruct { + iov_base: data1.as_ptr() as *mut libc::c_void, + iov_len: data1.len(), + }, + interface::IovecStruct { + iov_base: data2.as_ptr() as *mut libc::c_void, + iov_len: data2.len(), + }, + interface::IovecStruct { + iov_base: data3.as_ptr() as *mut libc::c_void, + iov_len: data3.len(), + }, + ]; + + // Write the data to the pipe using writev_syscall + let bytes_written = cage.writev_syscall(write_fd, iovec.as_ptr(), iovec.len() as i32); + assert_eq!( + bytes_written, + (data1.len() + data2.len() + data3.len()) as i32 + ); + + // Read the data from the pipe + let mut buffer = vec![0u8; data1.len() + data2.len() + data3.len()]; + let bytes_read = cage.read_syscall(read_fd, buffer.as_mut_ptr(), buffer.len()); + assert_eq!(bytes_read, buffer.len() as i32); + + // Verify that the data read is the same as the data written + let expected_data = [data1.as_ref(), data2.as_ref(), data3.as_ref()].concat(); + assert_eq!(buffer, expected_data); + + // Close both pipe file descriptors + assert_eq!(cage.close_syscall(read_fd), 0); + assert_eq!(cage.close_syscall(write_fd), 0); + + assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + lindrustfinalize(); + } - // Prepare the data to be written using an iovec structure + #[test] + fn ut_lind_fs_writev_file() { + // Acquiring a lock on TESTMUTEX prevents other tests from running concurrently, + // and also performs clean environment setup. + let _thelock = setup::lock_and_init(); + let cage = interface::cagetable_getref(1); - let data = b"Hello, pipe!"; - let iovec = interface::IovecStruct { - iov_base: data.as_ptr() as *mut libc::c_void, - iov_len: data.len(), - }; + // Define the file path + let file_path = "/tmp/test_writev_file"; - // Write the data to the pipe using writev_syscall - let bytes_written = cage.writev_syscall(write_fd, &iovec, 1); - assert_eq!(bytes_written, data.len() as i32); + // Open or create a file for writing + let fd = cage.open_syscall(file_path, O_CREAT | O_RDWR, S_IRWXA); + assert!(fd >= 0, "Failed to open file"); - // Read the data from the pipe - let mut buffer = vec![0u8; data.len()]; - let bytes_read = cage.read_syscall(read_fd, buffer.as_mut_ptr(), buffer.len()); - assert_eq!(bytes_read, data.len() as i32); + // Prepare the data to be written using an iovec structure + let data1 = b"Hello, "; + let data2 = b"world!"; + let expected_data = [data1.as_slice(), data2.as_slice()].concat(); // Concatenate slices for comparison + let iovecs = [ + interface::IovecStruct { + iov_base: data1.as_ptr() as *mut libc::c_void, + iov_len: data1.len(), + }, + interface::IovecStruct { + iov_base: data2.as_ptr() as *mut libc::c_void, + iov_len: data2.len(), + }, + ]; + + // Write the data to the file using writev_syscall + let total_len = expected_data.len() as i32; + let bytes_written = cage.writev_syscall(fd, iovecs.as_ptr(), iovecs.len() as i32); + assert_eq!(bytes_written, total_len); + + // Read the data back from the file + let mut buffer = vec![0u8; total_len as usize]; + cage.lseek_syscall(fd, 0, libc::SEEK_SET); // Seek to the beginning of the file + let bytes_read = cage.read_syscall(fd, buffer.as_mut_ptr(), buffer.len()); + assert_eq!(bytes_read, total_len); // Verify that the data read is the same as the data written - assert_eq!(buffer, data); + assert_eq!(buffer, expected_data); - assert_eq!(cage.close_syscall(read_fd), 0); - assert_eq!(cage.close_syscall(write_fd), 0); + // Close the file + assert_eq!(cage.close_syscall(fd), 0); + + // Clean up the file + assert_eq!(cage.unlink_syscall(file_path), 0); assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); lindrustfinalize();