github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/fuse/linux/setstat_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 <sys/uio.h>
    22  #include <unistd.h>
    23  #include <utime.h>
    24  
    25  #include <string>
    26  #include <vector>
    27  
    28  #include "gtest/gtest.h"
    29  #include "test/fuse/linux/fuse_fd_util.h"
    30  #include "test/util/cleanup.h"
    31  #include "test/util/fs_util.h"
    32  #include "test/util/fuse_util.h"
    33  #include "test/util/test_util.h"
    34  
    35  namespace gvisor {
    36  namespace testing {
    37  
    38  namespace {
    39  
    40  class SetStatTest : public FuseFdTest {
    41   public:
    42    void SetUp() override {
    43      FuseFdTest::SetUp();
    44      test_dir_path_ = JoinPath(mount_point_.path(), test_dir_);
    45      test_file_path_ = JoinPath(mount_point_.path(), test_file_);
    46    }
    47  
    48   protected:
    49    const uint64_t fh = 23;
    50    const std::string test_dir_ = "testdir";
    51    const std::string test_file_ = "testfile";
    52    const mode_t test_dir_mode_ = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
    53    const mode_t test_file_mode_ = S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR;
    54  
    55    std::string test_dir_path_;
    56    std::string test_file_path_;
    57  };
    58  
    59  TEST_F(SetStatTest, ChmodDir) {
    60    // Set up fixture.
    61    SetServerInodeLookup(test_dir_, test_dir_mode_);
    62    struct fuse_out_header out_header = {
    63        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
    64        .error = 0,
    65    };
    66    mode_t set_mode = S_IRGRP | S_IWGRP | S_IXGRP;
    67    struct fuse_attr_out out_payload = {
    68        .attr = DefaultFuseAttr(set_mode, 2),
    69    };
    70    auto iov_out = FuseGenerateIovecs(out_header, out_payload);
    71    SetServerResponse(FUSE_SETATTR, iov_out);
    72  
    73    // Make syscall.
    74    EXPECT_THAT(chmod(test_dir_path_.c_str(), set_mode), SyscallSucceeds());
    75  
    76    // Check FUSE request.
    77    struct fuse_in_header in_header;
    78    struct fuse_setattr_in in_payload;
    79    auto iov_in = FuseGenerateIovecs(in_header, in_payload);
    80  
    81    GetServerActualRequest(iov_in);
    82    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
    83    EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
    84    EXPECT_EQ(in_header.uid, 0);
    85    EXPECT_EQ(in_header.gid, 0);
    86    EXPECT_EQ(in_payload.valid, FATTR_MODE);
    87    EXPECT_EQ(in_payload.mode, S_IFDIR | set_mode);
    88  }
    89  
    90  TEST_F(SetStatTest, ChownDir) {
    91    // Set up fixture.
    92    SetServerInodeLookup(test_dir_, test_dir_mode_);
    93    struct fuse_out_header out_header = {
    94        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
    95        .error = 0,
    96    };
    97    struct fuse_attr_out out_payload = {
    98        .attr = DefaultFuseAttr(test_dir_mode_, 2),
    99    };
   100    auto iov_out = FuseGenerateIovecs(out_header, out_payload);
   101    SetServerResponse(FUSE_SETATTR, iov_out);
   102  
   103    // Make syscall.
   104    EXPECT_THAT(chown(test_dir_path_.c_str(), 1025, 1025), SyscallSucceeds());
   105  
   106    // Check FUSE request.
   107    struct fuse_in_header in_header;
   108    struct fuse_setattr_in in_payload;
   109    auto iov_in = FuseGenerateIovecs(in_header, in_payload);
   110  
   111    GetServerActualRequest(iov_in);
   112    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
   113    EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
   114    EXPECT_EQ(in_header.uid, 0);
   115    EXPECT_EQ(in_header.gid, 0);
   116    EXPECT_EQ(in_payload.valid, FATTR_UID | FATTR_GID);
   117    EXPECT_EQ(in_payload.uid, 1025);
   118    EXPECT_EQ(in_payload.gid, 1025);
   119  }
   120  
   121  TEST_F(SetStatTest, TruncateFile) {
   122    // Set up fixture.
   123    SetServerInodeLookup(test_file_, test_file_mode_);
   124    struct fuse_out_header out_header = {
   125        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
   126        .error = 0,
   127    };
   128    struct fuse_attr_out out_payload = {
   129        .attr = DefaultFuseAttr(S_IFREG | S_IRUSR | S_IWUSR, 2),
   130    };
   131    auto iov_out = FuseGenerateIovecs(out_header, out_payload);
   132    SetServerResponse(FUSE_SETATTR, iov_out);
   133  
   134    // Make syscall.
   135    EXPECT_THAT(truncate(test_file_path_.c_str(), 321), SyscallSucceeds());
   136  
   137    // Check FUSE request.
   138    struct fuse_in_header in_header;
   139    struct fuse_setattr_in in_payload;
   140    auto iov_in = FuseGenerateIovecs(in_header, in_payload);
   141  
   142    GetServerActualRequest(iov_in);
   143    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
   144    EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
   145    EXPECT_EQ(in_header.uid, 0);
   146    EXPECT_EQ(in_header.gid, 0);
   147    EXPECT_EQ(in_payload.valid, FATTR_SIZE);
   148    EXPECT_EQ(in_payload.size, 321);
   149  }
   150  
   151  TEST_F(SetStatTest, UtimeFile) {
   152    // Set up fixture.
   153    SetServerInodeLookup(test_file_, test_file_mode_);
   154    struct fuse_out_header out_header = {
   155        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
   156        .error = 0,
   157    };
   158    struct fuse_attr_out out_payload = {
   159        .attr = DefaultFuseAttr(S_IFREG | S_IRUSR | S_IWUSR, 2),
   160    };
   161    auto iov_out = FuseGenerateIovecs(out_header, out_payload);
   162    SetServerResponse(FUSE_SETATTR, iov_out);
   163  
   164    // Make syscall.
   165    time_t expected_atime = 1597159766, expected_mtime = 1597159765;
   166    struct utimbuf times = {
   167        .actime = expected_atime,
   168        .modtime = expected_mtime,
   169    };
   170    EXPECT_THAT(utime(test_file_path_.c_str(), &times), SyscallSucceeds());
   171  
   172    // Check FUSE request.
   173    struct fuse_in_header in_header;
   174    struct fuse_setattr_in in_payload;
   175    auto iov_in = FuseGenerateIovecs(in_header, in_payload);
   176  
   177    GetServerActualRequest(iov_in);
   178    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
   179    EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
   180    EXPECT_EQ(in_header.uid, 0);
   181    EXPECT_EQ(in_header.gid, 0);
   182    EXPECT_EQ(in_payload.valid, FATTR_ATIME | FATTR_MTIME);
   183    EXPECT_EQ(in_payload.atime, expected_atime);
   184    EXPECT_EQ(in_payload.mtime, expected_mtime);
   185  }
   186  
   187  TEST_F(SetStatTest, UtimesFile) {
   188    // Set up fixture.
   189    SetServerInodeLookup(test_file_, test_file_mode_);
   190    struct fuse_out_header out_header = {
   191        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
   192        .error = 0,
   193    };
   194    struct fuse_attr_out out_payload = {
   195        .attr = DefaultFuseAttr(test_file_mode_, 2),
   196    };
   197    auto iov_out = FuseGenerateIovecs(out_header, out_payload);
   198    SetServerResponse(FUSE_SETATTR, iov_out);
   199  
   200    // Make syscall.
   201    struct timeval expected_times[2] = {
   202        {
   203            .tv_sec = 1597159766,
   204            .tv_usec = 234945,
   205        },
   206        {
   207            .tv_sec = 1597159765,
   208            .tv_usec = 232341,
   209        },
   210    };
   211    EXPECT_THAT(utimes(test_file_path_.c_str(), expected_times),
   212                SyscallSucceeds());
   213  
   214    // Check FUSE request.
   215    struct fuse_in_header in_header;
   216    struct fuse_setattr_in in_payload;
   217    auto iov_in = FuseGenerateIovecs(in_header, in_payload);
   218  
   219    GetServerActualRequest(iov_in);
   220    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
   221    EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
   222    EXPECT_EQ(in_header.uid, 0);
   223    EXPECT_EQ(in_header.gid, 0);
   224    EXPECT_EQ(in_payload.valid, FATTR_ATIME | FATTR_MTIME);
   225    EXPECT_EQ(in_payload.atime, expected_times[0].tv_sec);
   226    EXPECT_EQ(in_payload.atimensec, expected_times[0].tv_usec * 1000);
   227    EXPECT_EQ(in_payload.mtime, expected_times[1].tv_sec);
   228    EXPECT_EQ(in_payload.mtimensec, expected_times[1].tv_usec * 1000);
   229  }
   230  
   231  TEST_F(SetStatTest, FtruncateFile) {
   232    // Set up fixture.
   233    SetServerInodeLookup(test_file_, test_file_mode_);
   234    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenPath(test_file_path_, O_RDWR, fh));
   235    auto close_fd = CloseFD(fd);
   236  
   237    struct fuse_out_header out_header = {
   238        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
   239        .error = 0,
   240    };
   241    struct fuse_attr_out out_payload = {
   242        .attr = DefaultFuseAttr(test_file_mode_, 2),
   243    };
   244    auto iov_out = FuseGenerateIovecs(out_header, out_payload);
   245    SetServerResponse(FUSE_SETATTR, iov_out);
   246  
   247    // Make syscall.
   248    EXPECT_THAT(ftruncate(fd.get(), 321), SyscallSucceeds());
   249  
   250    // Check FUSE request.
   251    struct fuse_in_header in_header;
   252    struct fuse_setattr_in in_payload;
   253    auto iov_in = FuseGenerateIovecs(in_header, in_payload);
   254  
   255    GetServerActualRequest(iov_in);
   256    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
   257    EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
   258    EXPECT_EQ(in_header.uid, 0);
   259    EXPECT_EQ(in_header.gid, 0);
   260    EXPECT_EQ(in_payload.valid, FATTR_SIZE | FATTR_FH);
   261    EXPECT_EQ(in_payload.fh, fh);
   262    EXPECT_EQ(in_payload.size, 321);
   263  }
   264  
   265  TEST_F(SetStatTest, FchmodFile) {
   266    // Set up fixture.
   267    SetServerInodeLookup(test_file_, test_file_mode_);
   268    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenPath(test_file_path_, O_RDWR, fh));
   269    auto close_fd = CloseFD(fd);
   270  
   271    struct fuse_out_header out_header = {
   272        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
   273        .error = 0,
   274    };
   275    mode_t set_mode = S_IROTH | S_IWOTH | S_IXOTH;
   276    struct fuse_attr_out out_payload = {
   277        .attr = DefaultFuseAttr(set_mode, 2),
   278    };
   279    auto iov_out = FuseGenerateIovecs(out_header, out_payload);
   280    SetServerResponse(FUSE_SETATTR, iov_out);
   281  
   282    // Make syscall.
   283    EXPECT_THAT(fchmod(fd.get(), set_mode), SyscallSucceeds());
   284  
   285    // Check FUSE request.
   286    struct fuse_in_header in_header;
   287    struct fuse_setattr_in in_payload;
   288    auto iov_in = FuseGenerateIovecs(in_header, in_payload);
   289  
   290    GetServerActualRequest(iov_in);
   291    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
   292    EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
   293    EXPECT_EQ(in_header.uid, 0);
   294    EXPECT_EQ(in_header.gid, 0);
   295    EXPECT_EQ(in_payload.valid, FATTR_MODE | FATTR_FH);
   296    EXPECT_EQ(in_payload.fh, fh);
   297    EXPECT_EQ(in_payload.mode, S_IFREG | set_mode);
   298  }
   299  
   300  TEST_F(SetStatTest, FchownFile) {
   301    // Set up fixture.
   302    SetServerInodeLookup(test_file_, test_file_mode_);
   303    auto fd = ASSERT_NO_ERRNO_AND_VALUE(OpenPath(test_file_path_, O_RDWR, fh));
   304    auto close_fd = CloseFD(fd);
   305  
   306    struct fuse_out_header out_header = {
   307        .len = sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out),
   308        .error = 0,
   309    };
   310    struct fuse_attr_out out_payload = {
   311        .attr = DefaultFuseAttr(S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR, 2),
   312    };
   313    auto iov_out = FuseGenerateIovecs(out_header, out_payload);
   314    SetServerResponse(FUSE_SETATTR, iov_out);
   315  
   316    // Make syscall.
   317    EXPECT_THAT(fchown(fd.get(), 1025, 1025), SyscallSucceeds());
   318  
   319    // Check FUSE request.
   320    struct fuse_in_header in_header;
   321    struct fuse_setattr_in in_payload;
   322    auto iov_in = FuseGenerateIovecs(in_header, in_payload);
   323  
   324    GetServerActualRequest(iov_in);
   325    EXPECT_EQ(in_header.len, sizeof(in_header) + sizeof(in_payload));
   326    EXPECT_EQ(in_header.opcode, FUSE_SETATTR);
   327    EXPECT_EQ(in_header.uid, 0);
   328    EXPECT_EQ(in_header.gid, 0);
   329    EXPECT_EQ(in_payload.valid, FATTR_UID | FATTR_GID | FATTR_FH);
   330    EXPECT_EQ(in_payload.fh, fh);
   331    EXPECT_EQ(in_payload.uid, 1025);
   332    EXPECT_EQ(in_payload.gid, 1025);
   333  }
   334  
   335  }  // namespace
   336  
   337  }  // namespace testing
   338  }  // namespace gvisor