diff --git a/repertory/librepertory/src/drives/fuse/fuse_drive.cpp b/repertory/librepertory/src/drives/fuse/fuse_drive.cpp index 3ce66361..77ae27a8 100644 --- a/repertory/librepertory/src/drives/fuse/fuse_drive.cpp +++ b/repertory/librepertory/src/drives/fuse/fuse_drive.cpp @@ -116,10 +116,17 @@ auto fuse_drive::create_impl(std::string api_path, mode_t mode, struct fuse_file_info *file_info) -> api_error { file_info->fh = 0U; + auto is_append_op = ((file_info->flags & O_APPEND) == O_APPEND); auto is_create_op = ((file_info->flags & O_CREAT) == O_CREAT); auto is_directory_op = ((file_info->flags & O_DIRECTORY) == O_DIRECTORY); auto is_exclusive = ((file_info->flags & O_EXCL) == O_EXCL); + auto is_read_write_op = ((file_info->flags & O_RDWR) == O_RDWR); auto is_truncate_op = ((file_info->flags & O_TRUNC) == O_TRUNC); + auto is_write_only_op = ((file_info->flags & O_WRONLY) == O_WRONLY); + + if (is_create_op && is_append_op && is_truncate_op) { + return api_error::invalid_operation; + } auto res = check_parent_access(api_path, X_OK); if (res != api_error::success) { @@ -142,8 +149,7 @@ auto fuse_drive::create_impl(std::string api_path, mode_t mode, return res; } - if ((((file_info->flags & O_WRONLY) == O_WRONLY) || - ((file_info->flags & O_RDWR) == O_RDWR)) && + if ((is_write_only_op || is_read_write_op) && not provider_.is_file_writeable(api_path)) { return api_error::permission_denied; } diff --git a/repertory/repertory_test/src/fuse_drive_create_and_open_test.cpp b/repertory/repertory_test/src/fuse_drive_create_and_open_test.cpp index 12615525..5bc902f7 100644 --- a/repertory/repertory_test/src/fuse_drive_create_and_open_test.cpp +++ b/repertory/repertory_test/src/fuse_drive_create_and_open_test.cpp @@ -376,8 +376,8 @@ TYPED_TEST(fuse_test, create_fails_with_excl_if_path_is_directory) { std::string dir_name{"create_test"}; auto dir_path = this->create_directory_and_test(dir_name); - for (auto &&mode : ops) { - auto handle = open(dir_path.c_str(), mode, ACCESSPERMS); + for (auto &&flags : ops) { + auto handle = open(dir_path.c_str(), flags, ACCESSPERMS); EXPECT_EQ(-1, handle); EXPECT_EQ(EEXIST, errno); @@ -395,12 +395,14 @@ TYPED_TEST(fuse_test, create_fails_with_excl_if_file_exists) { std::string file_name{"create_test"}; auto file_path = this->create_file_and_test(file_name); - for (auto &&mode : ops) { - auto handle = open(file_path.c_str(), mode, ACCESSPERMS); + + for (auto &&flags : ops) { + auto handle = open(file_path.c_str(), flags, ACCESSPERMS); EXPECT_EQ(-1, handle); EXPECT_EQ(EEXIST, errno); } + this->unlink_file_and_test(file_path); } @@ -417,12 +419,14 @@ TYPED_TEST(fuse_test, create_fails_if_path_is_directory) { std::string dir_name{"create_test"}; auto dir_path = this->create_directory_and_test(dir_name); - for (auto &&mode : ops) { - auto handle = open(dir_path.c_str(), mode, ACCESSPERMS); + + for (auto &&flags : ops) { + auto handle = open(dir_path.c_str(), flags, ACCESSPERMS); EXPECT_EQ(-1, handle); EXPECT_EQ(EISDIR, errno); } + this->rmdir_and_test(dir_path); } @@ -443,13 +447,29 @@ TYPED_TEST(fuse_test, create_fails_if_parent_path_does_not_exist) { std::string file_name{"no_dir/create_test"}; auto file_path = this->create_file_path(file_name); - for (auto &&mode : ops) { - auto handle = open(file_path.c_str(), mode, ACCESSPERMS); + for (auto &&flags : ops) { + auto handle = open(file_path.c_str(), flags, ACCESSPERMS); EXPECT_EQ(-1, handle); EXPECT_EQ(ENOENT, errno); } } + +TYPED_TEST(fuse_test, create_fails_if_invalid) { + std::array ops{ + O_CREAT | O_TRUNC | O_APPEND, + }; + + std::string file_name{"create_test"}; + auto file_path = this->create_file_path(file_name); + + for (auto &&flags : ops) { + auto handle = open(file_path.c_str(), flags, ACCESSPERMS); + EXPECT_EQ(-1, handle); + + EXPECT_EQ(EINVAL, errno); + } +} } // namespace repertory #endif // !defined(_WIN32)