19821f1d3SAlan Somers /*- 29821f1d3SAlan Somers * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 39821f1d3SAlan Somers * 49821f1d3SAlan Somers * Copyright (c) 2019 The FreeBSD Foundation 59821f1d3SAlan Somers * 69821f1d3SAlan Somers * This software was developed by BFF Storage Systems, LLC under sponsorship 79821f1d3SAlan Somers * from the FreeBSD Foundation. 89821f1d3SAlan Somers * 99821f1d3SAlan Somers * Redistribution and use in source and binary forms, with or without 109821f1d3SAlan Somers * modification, are permitted provided that the following conditions 119821f1d3SAlan Somers * are met: 129821f1d3SAlan Somers * 1. Redistributions of source code must retain the above copyright 139821f1d3SAlan Somers * notice, this list of conditions and the following disclaimer. 149821f1d3SAlan Somers * 2. Redistributions in binary form must reproduce the above copyright 159821f1d3SAlan Somers * notice, this list of conditions and the following disclaimer in the 169821f1d3SAlan Somers * documentation and/or other materials provided with the distribution. 179821f1d3SAlan Somers * 189821f1d3SAlan Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 199821f1d3SAlan Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 209821f1d3SAlan Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 219821f1d3SAlan Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 229821f1d3SAlan Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 239821f1d3SAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 249821f1d3SAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 259821f1d3SAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 269821f1d3SAlan Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 279821f1d3SAlan Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 289821f1d3SAlan Somers * SUCH DAMAGE. 299821f1d3SAlan Somers */ 309821f1d3SAlan Somers 319821f1d3SAlan Somers extern "C" { 329821f1d3SAlan Somers #include <fcntl.h> 339821f1d3SAlan Somers } 349821f1d3SAlan Somers 359821f1d3SAlan Somers #include "mockfs.hh" 369821f1d3SAlan Somers #include "utils.hh" 379821f1d3SAlan Somers 389821f1d3SAlan Somers using namespace testing; 399821f1d3SAlan Somers 409821f1d3SAlan Somers class Rmdir: public FuseTest { 419821f1d3SAlan Somers public: 426124fd71SAlan Somers void expect_getattr(uint64_t ino, mode_t mode) 436124fd71SAlan Somers { 446124fd71SAlan Somers EXPECT_CALL(*m_mock, process( 456124fd71SAlan Somers ResultOf([=](auto in) { 466124fd71SAlan Somers return (in->header.opcode == FUSE_GETATTR && 476124fd71SAlan Somers in->header.nodeid == ino); 486124fd71SAlan Somers }, Eq(true)), 496124fd71SAlan Somers _) 506124fd71SAlan Somers ).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto out) { 516124fd71SAlan Somers SET_OUT_HEADER_LEN(out, attr); 526124fd71SAlan Somers out->body.attr.attr.ino = ino; // Must match nodeid 536124fd71SAlan Somers out->body.attr.attr.mode = mode; 546124fd71SAlan Somers out->body.attr.attr_valid = UINT64_MAX; 556124fd71SAlan Somers }))); 566124fd71SAlan Somers } 576124fd71SAlan Somers 589821f1d3SAlan Somers void expect_lookup(const char *relpath, uint64_t ino) 599821f1d3SAlan Somers { 609821f1d3SAlan Somers EXPECT_LOOKUP(1, relpath) 619821f1d3SAlan Somers .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) { 629821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, entry); 639821f1d3SAlan Somers out->body.entry.attr.mode = S_IFDIR | 0755; 649821f1d3SAlan Somers out->body.entry.nodeid = ino; 659821f1d3SAlan Somers out->body.entry.attr.nlink = 2; 669821f1d3SAlan Somers }))); 679821f1d3SAlan Somers } 68*002e54b0SAlan Somers 69*002e54b0SAlan Somers void expect_rmdir(uint64_t parent, const char *relpath, int error) 70*002e54b0SAlan Somers { 71*002e54b0SAlan Somers EXPECT_CALL(*m_mock, process( 72*002e54b0SAlan Somers ResultOf([=](auto in) { 73*002e54b0SAlan Somers return (in->header.opcode == FUSE_RMDIR && 74*002e54b0SAlan Somers 0 == strcmp(relpath, in->body.rmdir) && 75*002e54b0SAlan Somers in->header.nodeid == parent); 76*002e54b0SAlan Somers }, Eq(true)), 77*002e54b0SAlan Somers _) 78*002e54b0SAlan Somers ).WillOnce(Invoke(ReturnErrno(error))); 79*002e54b0SAlan Somers } 809821f1d3SAlan Somers }; 819821f1d3SAlan Somers 82*002e54b0SAlan Somers /* 83*002e54b0SAlan Somers * A successful rmdir should clear the parent directory's attribute cache, 84*002e54b0SAlan Somers * because the fuse daemon should update its mtime and ctime 85*002e54b0SAlan Somers */ 86*002e54b0SAlan Somers TEST_F(Rmdir, clear_attr_cache) 87*002e54b0SAlan Somers { 88*002e54b0SAlan Somers const char FULLPATH[] = "mountpoint/some_dir"; 89*002e54b0SAlan Somers const char RELPATH[] = "some_dir"; 90*002e54b0SAlan Somers struct stat sb; 91*002e54b0SAlan Somers uint64_t ino = 42; 92*002e54b0SAlan Somers 93*002e54b0SAlan Somers EXPECT_CALL(*m_mock, process( 94*002e54b0SAlan Somers ResultOf([=](auto in) { 95*002e54b0SAlan Somers return (in->header.opcode == FUSE_GETATTR && 96*002e54b0SAlan Somers in->header.nodeid == 1); 97*002e54b0SAlan Somers }, Eq(true)), 98*002e54b0SAlan Somers _) 99*002e54b0SAlan Somers ).Times(2) 100*002e54b0SAlan Somers .WillRepeatedly(Invoke(ReturnImmediate([=](auto i __unused, auto out) { 101*002e54b0SAlan Somers SET_OUT_HEADER_LEN(out, attr); 102*002e54b0SAlan Somers out->body.attr.attr.ino = ino; // Must match nodeid 103*002e54b0SAlan Somers out->body.attr.attr.mode = S_IFDIR | 0755; 104*002e54b0SAlan Somers out->body.attr.attr_valid = UINT64_MAX; 105*002e54b0SAlan Somers }))); 106*002e54b0SAlan Somers expect_lookup(RELPATH, ino); 107*002e54b0SAlan Somers expect_rmdir(1, RELPATH, 0); 108*002e54b0SAlan Somers 109*002e54b0SAlan Somers ASSERT_EQ(0, rmdir(FULLPATH)) << strerror(errno); 110*002e54b0SAlan Somers EXPECT_EQ(0, stat("mountpoint", &sb)) << strerror(errno); 111*002e54b0SAlan Somers } 112*002e54b0SAlan Somers 1139821f1d3SAlan Somers TEST_F(Rmdir, enotempty) 1149821f1d3SAlan Somers { 1159821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_dir"; 1169821f1d3SAlan Somers const char RELPATH[] = "some_dir"; 1179821f1d3SAlan Somers uint64_t ino = 42; 1189821f1d3SAlan Somers 1196124fd71SAlan Somers expect_getattr(1, S_IFDIR | 0755); 1209821f1d3SAlan Somers expect_lookup(RELPATH, ino); 121*002e54b0SAlan Somers expect_rmdir(1, RELPATH, ENOTEMPTY); 1229821f1d3SAlan Somers 1239821f1d3SAlan Somers ASSERT_NE(0, rmdir(FULLPATH)); 1249821f1d3SAlan Somers ASSERT_EQ(ENOTEMPTY, errno); 1259821f1d3SAlan Somers } 1269821f1d3SAlan Somers 1279821f1d3SAlan Somers TEST_F(Rmdir, ok) 1289821f1d3SAlan Somers { 1299821f1d3SAlan Somers const char FULLPATH[] = "mountpoint/some_dir"; 1309821f1d3SAlan Somers const char RELPATH[] = "some_dir"; 1319821f1d3SAlan Somers uint64_t ino = 42; 1329821f1d3SAlan Somers 1336124fd71SAlan Somers expect_getattr(1, S_IFDIR | 0755); 1349821f1d3SAlan Somers expect_lookup(RELPATH, ino); 135*002e54b0SAlan Somers expect_rmdir(1, RELPATH, 0); 1369821f1d3SAlan Somers 1379821f1d3SAlan Somers ASSERT_EQ(0, rmdir(FULLPATH)) << strerror(errno); 1389821f1d3SAlan Somers } 139