Fix how O_PATH interacts with other flags

This commit is contained in:
Ruihan Li 2025-11-10 22:00:26 +08:00 committed by Tate, Hongliang Tian
parent 25beca462d
commit 277b5b5c24
3 changed files with 36 additions and 3 deletions

View File

@ -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)

View File

@ -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

View File

@ -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));