Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/fs/fusefs/rmdir.cc
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2019 The FreeBSD Foundation
5
*
6
* This software was developed by BFF Storage Systems, LLC under sponsorship
7
* from the FreeBSD Foundation.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
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.
17
*
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
28
* SUCH DAMAGE.
29
*/
30
31
extern "C" {
32
#include <fcntl.h>
33
#include <semaphore.h>
34
}
35
36
#include "mockfs.hh"
37
#include "utils.hh"
38
39
using namespace testing;
40
41
class Rmdir: public FuseTest {
42
public:
43
void expect_lookup(const char *relpath, uint64_t ino, int times=1)
44
{
45
EXPECT_LOOKUP(FUSE_ROOT_ID, relpath)
46
.Times(times)
47
.WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
48
SET_OUT_HEADER_LEN(out, entry);
49
out.body.entry.attr_valid = UINT64_MAX;
50
out.body.entry.attr.mode = S_IFDIR | 0755;
51
out.body.entry.nodeid = ino;
52
out.body.entry.attr.nlink = 2;
53
})));
54
}
55
56
void expect_rmdir(uint64_t parent, const char *relpath, int error)
57
{
58
EXPECT_CALL(*m_mock, process(
59
ResultOf([=](auto in) {
60
return (in.header.opcode == FUSE_RMDIR &&
61
0 == strcmp(relpath, in.body.rmdir) &&
62
in.header.nodeid == parent);
63
}, Eq(true)),
64
_)
65
).WillOnce(Invoke(ReturnErrno(error)));
66
}
67
};
68
69
/*
70
* A successful rmdir should clear the parent directory's attribute cache,
71
* because the fuse daemon should update its mtime and ctime
72
*/
73
TEST_F(Rmdir, parent_attr_cache)
74
{
75
const char FULLPATH[] = "mountpoint/some_dir";
76
const char RELPATH[] = "some_dir";
77
struct stat sb;
78
sem_t sem;
79
uint64_t ino = 42;
80
Sequence seq;
81
82
ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno);
83
84
expect_lookup(RELPATH, ino);
85
EXPECT_CALL(*m_mock, process(
86
ResultOf([=](auto in) {
87
return (in.header.opcode == FUSE_RMDIR &&
88
0 == strcmp(RELPATH, in.body.rmdir) &&
89
in.header.nodeid == FUSE_ROOT_ID);
90
}, Eq(true)),
91
_)
92
).InSequence(seq)
93
.WillOnce(Invoke(ReturnErrno(0)));
94
expect_forget(ino, 1, &sem);
95
EXPECT_CALL(*m_mock, process(
96
ResultOf([=](auto in) {
97
return (in.header.opcode == FUSE_GETATTR &&
98
in.header.nodeid == FUSE_ROOT_ID);
99
}, Eq(true)),
100
_)
101
).InSequence(seq)
102
.WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
103
SET_OUT_HEADER_LEN(out, attr);
104
out.body.attr.attr.ino = FUSE_ROOT_ID;
105
out.body.attr.attr.mode = S_IFDIR | 0755;
106
out.body.attr.attr_valid = UINT64_MAX;
107
})));
108
109
ASSERT_EQ(0, rmdir(FULLPATH)) << strerror(errno);
110
EXPECT_EQ(0, stat("mountpoint", &sb)) << strerror(errno);
111
sem_wait(&sem);
112
sem_destroy(&sem);
113
}
114
115
TEST_F(Rmdir, enotempty)
116
{
117
const char FULLPATH[] = "mountpoint/some_dir";
118
const char RELPATH[] = "some_dir";
119
uint64_t ino = 42;
120
121
expect_lookup(RELPATH, ino);
122
expect_rmdir(FUSE_ROOT_ID, RELPATH, ENOTEMPTY);
123
124
ASSERT_NE(0, rmdir(FULLPATH));
125
ASSERT_EQ(ENOTEMPTY, errno);
126
}
127
128
/* Removing a directory should expire its entry cache */
129
TEST_F(Rmdir, entry_cache)
130
{
131
const char FULLPATH[] = "mountpoint/some_dir";
132
const char RELPATH[] = "some_dir";
133
sem_t sem;
134
uint64_t ino = 42;
135
136
expect_lookup(RELPATH, ino, 2);
137
expect_rmdir(FUSE_ROOT_ID, RELPATH, 0);
138
expect_forget(ino, 1, &sem);
139
140
ASSERT_EQ(0, rmdir(FULLPATH)) << strerror(errno);
141
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
142
sem_wait(&sem);
143
sem_destroy(&sem);
144
}
145
146
TEST_F(Rmdir, ok)
147
{
148
const char FULLPATH[] = "mountpoint/some_dir";
149
const char RELPATH[] = "some_dir";
150
sem_t sem;
151
uint64_t ino = 42;
152
153
ASSERT_EQ(0, sem_init(&sem, 0, 0)) << strerror(errno);
154
155
expect_lookup(RELPATH, ino);
156
expect_rmdir(FUSE_ROOT_ID, RELPATH, 0);
157
expect_forget(ino, 1, &sem);
158
159
ASSERT_EQ(0, rmdir(FULLPATH)) << strerror(errno);
160
sem_wait(&sem);
161
sem_destroy(&sem);
162
}
163
164