diff --git a/kernel/src/fs/path/mod.rs b/kernel/src/fs/path/mod.rs index 3ec441715..f3fc507fc 100644 --- a/kernel/src/fs/path/mod.rs +++ b/kernel/src/fs/path/mod.rs @@ -446,7 +446,10 @@ impl Path { ); } - if inode_type.is_regular_file() && creation_flags.contains(CreationFlags::O_TRUNC) { + if inode_type.is_regular_file() + && creation_flags.contains(CreationFlags::O_TRUNC) + && !open_args.status_flags.contains(StatusFlags::O_PATH) + { self.resize(0)?; } InodeHandle::new(self.clone(), open_args.access_mode, open_args.status_flags) diff --git a/kernel/src/syscall/open.rs b/kernel/src/syscall/open.rs index 7e63d4ac0..c0d5d1580 100644 --- a/kernel/src/syscall/open.rs +++ b/kernel/src/syscall/open.rs @@ -6,7 +6,7 @@ use crate::{ file_table::{FdFlags, FileDesc}, fs_resolver::{FsPath, FsResolver, LookupResult, AT_FDCWD}, inode_handle::InodeHandle, - utils::{AccessMode, CreationFlags, InodeMode, InodeType, OpenArgs}, + utils::{AccessMode, CreationFlags, InodeMode, InodeType, OpenArgs, StatusFlags}, }, prelude::*, syscall::constants::MAX_FILENAME_LEN, @@ -89,7 +89,9 @@ fn do_open( let inode_handle = match lookup_res { LookupResult::Resolved(target_path) => target_path.open(open_args)?, LookupResult::AtParent(result) => { - if !open_args.creation_flags.contains(CreationFlags::O_CREAT) { + if !open_args.creation_flags.contains(CreationFlags::O_CREAT) + || open_args.status_flags.contains(StatusFlags::O_PATH) + { return_errno_with_message!(Errno::ENOENT, "the file does not exist"); } if open_args diff --git a/test/src/apps/file_io/access_err.c b/test/src/apps/file_io/access_err.c index ca9eafe0f..edaa3c5f2 100644 --- a/test/src/apps/file_io/access_err.c +++ b/test/src/apps/file_io/access_err.c @@ -232,6 +232,34 @@ FN_TEST(path) } END_TEST() +FN_TEST(flags) +{ + int fd; + char buf[5]; + + fd = TEST_SUCC(open(FILENAME, O_WRONLY)); + TEST_RES(write(fd, "hello", 5), _ret == 5); + TEST_SUCC(close(fd)); + + // `O_PATH | O_TRUNC` has no effect. + fd = TEST_SUCC(open(FILENAME, O_WRONLY | O_PATH | O_TRUNC)); + TEST_SUCC(close(fd)); + fd = TEST_SUCC(open(FILENAME, O_RDONLY)); + TEST_RES(read(fd, buf, sizeof(buf)), + _ret == 5 && memcmp(buf, "hello", 5) == 0); + TEST_SUCC(close(fd)); + + // `O_RDONLY | O_TRUNC` will truncate the file. + fd = TEST_SUCC(open(FILENAME, O_RDONLY | O_TRUNC)); + TEST_RES(read(fd, buf, sizeof(buf)), _ret == 0); + TEST_SUCC(close(fd)); + + // `O_PATH | O_CREAT` has no effect. + TEST_ERRNO(open("/tmp/file_does_not_exist", O_PATH | O_CREAT, 0644), + ENOENT); +} +END_TEST() + FN_SETUP(unlink) { CHECK(unlink(FILENAME));