2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2019 The FreeBSD Foundation
6 * This software was developed by BFF Storage Systems, LLC under sponsorship
7 * from the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 using namespace testing;
40 class Open: public FuseTest {
44 /* Test an OK open of a file with the given flags */
45 void test_ok(int os_flags, int fuse_flags) {
46 const char FULLPATH[] = "mountpoint/some_file.txt";
47 const char RELPATH[] = "some_file.txt";
51 FuseTest::expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
52 EXPECT_CALL(*m_mock, process(
53 ResultOf([=](auto in) {
54 return (in->header.opcode == FUSE_OPEN &&
55 in->body.open.flags == (uint32_t)fuse_flags &&
56 in->header.nodeid == ino);
59 ).WillOnce(Invoke(ReturnImmediate([](auto in __unused, auto out) {
60 out->header.len = sizeof(out->header);
61 SET_OUT_HEADER_LEN(out, open);
64 /* Until the attr cache is working, we may send an additional GETATTR */
65 EXPECT_CALL(*m_mock, process(
66 ResultOf([=](auto in) {
67 return (in->header.opcode == FUSE_GETATTR &&
68 in->header.nodeid == ino);
71 ).WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto out) {
72 SET_OUT_HEADER_LEN(out, attr);
73 out->body.attr.attr.ino = ino; // Must match nodeid
74 out->body.attr.attr.mode = S_IFREG | 0644;
77 fd = open(FULLPATH, os_flags);
78 EXPECT_LE(0, fd) << strerror(errno);
79 /* Deliberately leak fd. close(2) will be tested in release.cc */
85 * fusefs(5) does not support I/O on device nodes (neither does UFS). But it
90 const char FULLPATH[] = "mountpoint/zero";
91 const char RELPATH[] = "zero";
94 EXPECT_LOOKUP(1, RELPATH)
95 .WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
96 SET_OUT_HEADER_LEN(out, entry);
97 out->body.entry.attr.mode = S_IFCHR | 0644;
98 out->body.entry.nodeid = ino;
99 out->body.entry.attr.nlink = 1;
100 out->body.entry.attr_valid = UINT64_MAX;
101 out->body.entry.attr.rdev = 44; /* /dev/zero's rdev */
104 ASSERT_EQ(-1, open(FULLPATH, O_RDONLY));
105 EXPECT_EQ(EOPNOTSUPP, errno);
109 * The fuse daemon fails the request with enoent. This usually indicates a
110 * race condition: some other FUSE client removed the file in between when the
111 * kernel checked for it with lookup and tried to open it
115 const char FULLPATH[] = "mountpoint/some_file.txt";
116 const char RELPATH[] = "some_file.txt";
119 expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
120 EXPECT_CALL(*m_mock, process(
121 ResultOf([=](auto in) {
122 return (in->header.opcode == FUSE_OPEN &&
123 in->header.nodeid == ino);
126 ).WillOnce(Invoke(ReturnErrno(ENOENT)));
127 EXPECT_NE(0, open(FULLPATH, O_RDONLY));
128 EXPECT_EQ(ENOENT, errno);
132 * The daemon is responsible for checking file permissions (unless the
133 * default_permissions mount option was used)
137 const char FULLPATH[] = "mountpoint/some_file.txt";
138 const char RELPATH[] = "some_file.txt";
141 expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1);
142 EXPECT_CALL(*m_mock, process(
143 ResultOf([=](auto in) {
144 return (in->header.opcode == FUSE_OPEN &&
145 in->header.nodeid == ino);
148 ).WillOnce(Invoke(ReturnErrno(EPERM)));
149 EXPECT_NE(0, open(FULLPATH, O_RDONLY));
150 EXPECT_EQ(EPERM, errno);
153 /* fusefs(5) does not yet support I/O on fifos. But it shouldn't crash. */
156 const char FULLPATH[] = "mountpoint/zero";
157 const char RELPATH[] = "zero";
160 EXPECT_LOOKUP(1, RELPATH)
161 .WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
162 SET_OUT_HEADER_LEN(out, entry);
163 out->body.entry.attr.mode = S_IFIFO | 0644;
164 out->body.entry.nodeid = ino;
165 out->body.entry.attr.nlink = 1;
166 out->body.entry.attr_valid = UINT64_MAX;
169 ASSERT_EQ(-1, open(FULLPATH, O_RDONLY));
170 EXPECT_EQ(EOPNOTSUPP, errno);
173 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236340 */
174 TEST_F(Open, DISABLED_o_append)
176 test_ok(O_WRONLY | O_APPEND, O_WRONLY | O_APPEND);
179 /* The kernel is supposed to filter out this flag */
180 TEST_F(Open, o_creat)
182 test_ok(O_WRONLY | O_CREAT, O_WRONLY);
185 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236340 */
186 TEST_F(Open, DISABLED_o_direct)
188 test_ok(O_WRONLY | O_DIRECT, O_WRONLY | O_DIRECT);
191 /* The kernel is supposed to filter out this flag */
194 test_ok(O_WRONLY | O_EXCL, O_WRONLY);
197 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236329 */
198 TEST_F(Open, DISABLED_o_exec)
200 test_ok(O_EXEC, O_EXEC);
203 /* The kernel is supposed to filter out this flag */
204 TEST_F(Open, o_noctty)
206 test_ok(O_WRONLY | O_NOCTTY, O_WRONLY);
209 TEST_F(Open, o_rdonly)
211 test_ok(O_RDONLY, O_RDONLY);
214 /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236340 */
215 TEST_F(Open, DISABLED_o_trunc)
217 test_ok(O_WRONLY | O_TRUNC, O_WRONLY | O_TRUNC);
220 TEST_F(Open, o_wronly)
222 test_ok(O_WRONLY, O_WRONLY);
227 test_ok(O_RDWR, O_RDWR);