github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/fuse/linux/create_test.cc (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <errno.h>
    16  #include <fcntl.h>
    17  #include <linux/fuse.h>
    18  #include <sys/stat.h>
    19  #include <sys/statfs.h>
    20  #include <sys/types.h>
    21  #include <unistd.h>
    22  
    23  #include <string>
    24  
    25  #include "gtest/gtest.h"
    26  #include "test/fuse/linux/fuse_base.h"
    27  #include "test/util/fs_util.h"
    28  #include "test/util/fuse_util.h"
    29  #include "test/util/temp_umask.h"
    30  #include "test/util/test_util.h"
    31  
    32  namespace gvisor {
    33  namespace testing {
    34  
    35  namespace {
    36  
    37  class CreateTest : public FuseTest {
    38   protected:
    39    const std::string test_file_name_ = "test_file";
    40    const mode_t mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
    41  };
    42  
    43  TEST_F(CreateTest, CreateFile) {
    44    const std::string test_file_path =
    45        JoinPath(mount_point_.path().c_str(), test_file_name_);
    46  
    47    // Ensure the file doesn't exist.
    48    struct fuse_out_header out_header = {
    49        .len = sizeof(struct fuse_out_header),
    50        .error = -ENOENT,
    51    };
    52    auto iov_out = FuseGenerateIovecs(out_header);
    53    SetServerResponse(FUSE_LOOKUP, iov_out);
    54  
    55    // creat(2) is equal to open(2) with open_flags O_CREAT | O_WRONLY | O_TRUNC.
    56    const mode_t new_mask = S_IWGRP | S_IWOTH;
    57    const int open_flags = O_CREAT | O_WRONLY | O_TRUNC;
    58    out_header.error = 0;
    59    out_header.len = sizeof(struct fuse_out_header) +
    60                     sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out);
    61    struct fuse_entry_out entry_payload = DefaultEntryOut(mode & ~new_mask, 2);
    62    struct fuse_open_out out_payload = {
    63        .fh = 1,
    64        .open_flags = open_flags,
    65    };
    66    iov_out = FuseGenerateIovecs(out_header, entry_payload, out_payload);
    67    SetServerResponse(FUSE_CREATE, iov_out);
    68  
    69    // kernfs generates a successive FUSE_OPEN after the file is created. Linux's
    70    // fuse kernel module will not send this FUSE_OPEN after creat(2).
    71    out_header.len =
    72        sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out);
    73    iov_out = FuseGenerateIovecs(out_header, out_payload);
    74    SetServerResponse(FUSE_OPEN, iov_out);
    75  
    76    int fd;
    77    TempUmask mask(new_mask);
    78    EXPECT_THAT(fd = creat(test_file_path.c_str(), mode), SyscallSucceeds());
    79    EXPECT_THAT(fcntl(fd, F_GETFL),
    80                SyscallSucceedsWithValue(open_flags & O_ACCMODE));
    81  
    82    struct fuse_in_header in_header;
    83    struct fuse_create_in in_payload;
    84    std::vector<char> name(test_file_name_.size() + 1);
    85    auto iov_in = FuseGenerateIovecs(in_header, in_payload, name);
    86  
    87    // Skip the request of FUSE_LOOKUP.
    88    SkipServerActualRequest();
    89  
    90    // Get the first FUSE_CREATE.
    91    GetServerActualRequest(iov_in);
    92    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload) +
    93                                 test_file_name_.size() + 1);
    94    EXPECT_EQ(in_header.opcode, FUSE_CREATE);
    95    EXPECT_EQ(in_payload.flags, open_flags);
    96    EXPECT_EQ(in_payload.mode, mode & ~new_mask);
    97    EXPECT_EQ(in_payload.umask, new_mask);
    98    EXPECT_EQ(std::string(name.data()), test_file_name_);
    99  
   100    // Get the successive FUSE_OPEN.
   101    struct fuse_open_in in_payload_open;
   102    iov_in = FuseGenerateIovecs(in_header, in_payload_open);
   103    GetServerActualRequest(iov_in);
   104    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload_open));
   105    EXPECT_EQ(in_header.opcode, FUSE_OPEN);
   106    EXPECT_EQ(in_payload_open.flags, open_flags & O_ACCMODE);
   107  
   108    EXPECT_THAT(close(fd), SyscallSucceeds());
   109    // Skip the FUSE_RELEASE.
   110    SkipServerActualRequest();
   111  }
   112  
   113  TEST_F(CreateTest, CreateFileAlreadyExists) {
   114    const std::string test_file_path =
   115        JoinPath(mount_point_.path().c_str(), test_file_name_);
   116  
   117    const int open_flags = O_CREAT | O_EXCL;
   118  
   119    SetServerInodeLookup(test_file_name_);
   120  
   121    EXPECT_THAT(open(test_file_path.c_str(), mode, open_flags),
   122                SyscallFailsWithErrno(EEXIST));
   123  }
   124  
   125  }  // namespace
   126  
   127  }  // namespace testing
   128  }  // namespace gvisor