/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2019 The FreeBSD Foundation4*5* This software was developed by BFF Storage Systems, LLC under sponsorship6* from the FreeBSD Foundation.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF27* SUCH DAMAGE.28*/2930extern "C" {31#include <dirent.h>32#include <fcntl.h>33}3435#include "mockfs.hh"36#include "utils.hh"3738using namespace testing;3940class ReleaseDir: public FuseTest {4142public:43void expect_lookup(const char *relpath, uint64_t ino)44{45FuseTest::expect_lookup(relpath, ino, S_IFDIR | 0755, 0, 1);46}47};4849/* If a file descriptor is duplicated, only the last close causes RELEASE */50TEST_F(ReleaseDir, dup)51{52const char FULLPATH[] = "mountpoint/some_file.txt";53const char RELPATH[] = "some_file.txt";54uint64_t ino = 42;55DIR *dir, *dir2;5657expect_lookup(RELPATH, ino);58expect_opendir(ino);59EXPECT_CALL(*m_mock, process(60ResultOf([=](auto in) {61return (in.header.opcode == FUSE_READDIR &&62in.header.nodeid == ino &&63in.body.readdir.offset == 0);64}, Eq(true)),65_)66).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {67out.header.error = 0;68out.header.len = sizeof(out.header);69})));70expect_releasedir(ino, ReturnErrno(0));7172dir = opendir(FULLPATH);73ASSERT_NE(nullptr, dir) << strerror(errno);7475dir2 = fdopendir(dup(dirfd(dir)));76ASSERT_NE(nullptr, dir2) << strerror(errno);7778ASSERT_EQ(0, closedir(dir)) << strerror(errno);79ASSERT_EQ(0, closedir(dir2)) << strerror(errno);80}8182TEST_F(ReleaseDir, ok)83{84const char FULLPATH[] = "mountpoint/some_dir";85const char RELPATH[] = "some_dir";86uint64_t ino = 42;87DIR *dir;8889expect_lookup(RELPATH, ino);90expect_opendir(ino);91expect_releasedir(ino, ReturnErrno(0));9293dir = opendir(FULLPATH);94ASSERT_NE(nullptr, dir) << strerror(errno);9596ASSERT_EQ(0, closedir(dir)) << strerror(errno);97}9899/* Directories opened O_EXEC should be properly released, too */100TEST_F(ReleaseDir, o_exec)101{102const char FULLPATH[] = "mountpoint/some_dir";103const char RELPATH[] = "some_dir";104uint64_t ino = 42;105int fd;106107expect_lookup(RELPATH, ino);108expect_opendir(ino);109expect_releasedir(ino, ReturnErrno(0));110111fd = open(FULLPATH, O_EXEC | O_DIRECTORY);112ASSERT_LE(0, fd) << strerror(errno);113114ASSERT_EQ(0, close(fd)) << strerror(errno);115}116117118